home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Storage / Bento / CMDraft.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  152.3 KB  |  5,306 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        CMDraft.cpp
  3.  
  4.     Contains:    Implementation for CMDraft class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <27>      12/17/96    CC        1609278: CloneMovedFrame: Set containing
  13.                                     frame to NULL after attaching to part.
  14.         <26>      11/19/96    CC        1354893 Create new frames during move to
  15.                                     simplify in-limbo recipes.
  16.                                     1603008 Weak clone of non-persistent frames
  17.                                     crashes in IsLinkObject,
  18.                                     IsLinkSourceObject, & GetStorageUnitType.
  19.         <25>      11/19/96    EL        1343891: redo checkin 23 because 24 wipes
  20.                                     out 23.
  21.         <24>     10/7/96    RA        1343748: Store editor user string in SU and
  22.                                     use it in NoPart if possible
  23.         <23>     10/4/96    EL        1343891: if editor not found, see if there
  24.                                     is one for the other CPU.
  25.         <22>     9/19/96    DH        Task: low memory changes. Added comments
  26.                                     for future low-mem changes.
  27.         <21>     9/13/96    EL        1366287: when asking for a specific editor
  28.                                     in ConstructRealPart, don't substitue
  29.                                     NoPart
  30.         <20>     8/13/96    DM        1362809: in CloseVersion(), close embedded
  31.                                     container before release, fatal error on
  32.                                     failure
  33.         <19>     7/31/96    DH        #1373676:Fixed ConstructRealPart so that
  34.                                     the real part will not be set erroneously.
  35.         <18>     7/25/96    DH        Fixed NewCMxx methods to check the
  36.                                     somClassReference allocation and throw if
  37.                                     null (No bug #, approved by Bern).
  38.         <17>     7/23/96    DH        Bug# 1371089: OD crashes when parts throw
  39.                                     out of InitPartFromStorage: Approved by
  40.                                     Bern.
  41.         <16>     7/11/96    jpa        1364071: Don't pass "NoPart" as preferred
  42.                                     editor name to NoPart. Catch
  43.                                     kODErrOutOfMemory when creating parts.
  44.         <15>     6/27/96    EL        1361735: if no editor user string, use SOM
  45.                                     class name
  46.         <14>     6/27/96    jpa        1361886: ConstructRealPart sets NoPart user
  47.                                     message.
  48.         <13>     6/23/96    EL        1344140: if out of memory when new part is
  49.                                     initialized, tread as cannot load part.
  50.         <12>     6/22/96    EL        1344140: put up alert if we cannot create
  51.                                     part.
  52.         <11>     5/30/96    CC        1332786: Add std prefix to private property
  53.                                     & value type.
  54.         <10>     5/24/96    jpa        1246074: SOM_CATCH --> SOM_TRY..SOM_ENDTRY
  55.          <8>     3/22/96    CC        1330388: Support direct clone between
  56.                                     document drafts.
  57.          <7>     3/15/96    DM        1295410: create list iterators on stack
  58.                                     (avoid mem thrash during purge)
  59.                                     1292140: throw when persistent object has
  60.                                     no storage unit getting draft or session
  61.          <6>     3/15/96    CC        1316917: Don't remove valuable data
  62.                                     interchange properties when cloning with
  63.                                     kODCloneAll.
  64.          <5>     3/13/96    VL        1305064: Removed class purging code as it
  65.                                     is done by SOM now.
  66.          <4>      3/8/96    EL        1308013: If loading of editor fails,
  67.                                     replace by NoPart. Code reviewed by DM.
  68.          <3>     1/16/96    VL        1170098: Emptied out PartDeleted and
  69.                                     PartInstantiated as they are no longer
  70.                                     needed.
  71.          <2>     1/15/96    TJ        Cleaned Up
  72.  
  73.     To Do:
  74.     In Progress:
  75.         
  76. */
  77.  
  78. #define CMDraft_Class_Source
  79. #define VARIABLE_MACROS
  80. #include <CMDraft.xih>
  81.  
  82. #ifndef _DRAFPRIV_
  83. #include "DrafPriv.h"
  84. #endif
  85.  
  86. #ifndef SOM_ODSession_xh
  87. #include <ODSessn.xh>
  88. #endif
  89.  
  90. #ifndef SOM_CMDocument_xh
  91. #include <CMDoc.xh>
  92. #endif
  93.  
  94. #ifndef SOM_CMStorageUnit_xh
  95. #include <CMSU.xh>
  96. #endif
  97.  
  98. #ifndef _DOCPRIV_
  99. #include "DocPriv.h"
  100. #endif
  101.  
  102. #ifndef SOM_ODContainer_xh
  103. #include <ODCtr.xh>
  104. #endif
  105.  
  106. #ifndef SOM_ODStorageSystem_xh
  107. #include <ODStor.xh>
  108. #endif
  109.  
  110. #ifndef SOM_ODStorageUnitCursor_xh
  111. #include <SUCursor.xh>
  112. #endif
  113.  
  114. #ifndef SOM_ODFrame_xh
  115. #include <Frame.xh>
  116. #endif
  117.  
  118. #ifndef SOM_ODLink_xh
  119. #include <Link.xh>
  120. #endif
  121.  
  122. #ifndef SOM_ODLinkSource_xh
  123. #include <LinkSrc.xh>
  124. #endif
  125.  
  126. #ifndef SOM_ODLinkSpec_xh
  127. #include <LinkSpec.xh>
  128. #endif
  129.  
  130. #ifndef SOM_ODLinkManager_xh
  131. #include <LinkMgr.xh>
  132. #endif
  133.  
  134. #ifndef SOM_ODPart_xh
  135. #include <Part.xh>
  136. #endif
  137.  
  138. #ifndef _EXCEPT_
  139. #include "Except.h"
  140. #endif
  141.  
  142. #ifndef SOM_ODBentoContainer_xh
  143. #include "CMCtr.xh"
  144. #endif
  145.  
  146. #ifndef _CMAPI_
  147. #include "CMAPI.h"
  148. #endif
  149.  
  150. #ifndef __CM_API_TYPE_
  151. #include "CMAPITYP.h"
  152. #endif
  153.  
  154. #ifndef SOM_ODEmbeddedContainer_xh
  155. #include <EmbedCtr.xh>
  156. #endif
  157.  
  158. #ifndef _SESSHDR_
  159. #include "SessHdr.h"
  160. #endif
  161.  
  162. #ifndef _ODMEMORY_
  163. #include "ODMemory.h"
  164. #endif
  165.  
  166. #ifndef _ODNEW_
  167. #include "ODNew.h"
  168. #endif
  169.  
  170. #ifndef SOM_Module_OpenDoc_StdProps_defined
  171. #include <StdProps.xh>
  172. #endif
  173.  
  174. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  175. #include <StdTypes.xh>
  176. #endif
  177.  
  178. #ifndef SOM_CMLinkIterator_xh
  179. #include <CMLkItr.xh>
  180. #endif
  181.  
  182. #ifndef SOM_CMLinkSourceIterator_xh
  183. #include <CMLkSItr.xh>
  184. #endif
  185.  
  186. #ifndef _INDHDR_
  187. #include "IndHdr.h"            // for some const ODName
  188. #endif
  189.  
  190. #ifndef _OPENHASH_
  191. #include "OpenHash.h"
  192. #endif
  193.  
  194. #ifndef _ISOSTR_
  195. #include "ISOStr.h"
  196. #endif
  197.  
  198. #ifndef __STRING__
  199. #include <string.h>            // For strlen, strcpy....
  200. #endif
  201.  
  202. #ifndef _ODDEBUG_
  203. #include <ODDebug.h>
  204. #endif
  205.  
  206. #ifndef _STORUTIL_
  207. #include <StorUtil.h>
  208. #endif
  209.  
  210. #ifndef SOM_ODBinding_xh
  211. #include <ODBindng.xh>
  212. #endif
  213.  
  214. #ifndef SOM_ODPartWrapper_xh
  215. #include <PartWrap.xh>
  216. #endif
  217.  
  218. #ifndef _BENTODEF_
  219. #include "BentoDef.h"
  220. #endif
  221.  
  222. #ifndef _BARRAY_
  223. #include <BArray.h>
  224. #endif
  225.  
  226. #ifndef _UTILERRS_
  227. #include "UtilErrs.h"
  228. #endif
  229.  
  230. #ifndef SOM_ODDragAndDrop_xh
  231. #include <DragDrp.xh>
  232. #endif
  233.  
  234. #ifndef SOM_ODArbitrator_xh
  235. #include <Arbitrat.xh>
  236. #endif
  237.  
  238. #ifndef SOM_Module_OpenDoc_Foci_defined
  239. #include <Foci.xh>
  240. #endif
  241.  
  242. #ifndef _ODNEWOBJ_
  243. #include <ODNewObj.h>
  244. #endif
  245.  
  246. #ifndef _STDTYPIO_
  247. #include <StdTypIO.h>
  248. #endif
  249.  
  250. #ifndef _TEMPOBJ_
  251. #include <TempObj.h>
  252. #endif
  253.  
  254. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  255. #include <StdDefs.xh>
  256. #endif
  257.  
  258. #ifndef SOM_SOMClassMgr_xh
  259. #include <somcm.xh>
  260. #endif
  261.  
  262. #ifndef SOM_ODNameSpaceManager_xh
  263. #include <NmSpcMg.xh>
  264. #endif
  265.  
  266. #ifndef SOM_ODNameSpace_xh
  267. #include <NamSpac.xh>
  268. #endif
  269.  
  270. #ifndef _NMSPCUTL_
  271. #include "NmSpcUtl.h"
  272. #endif
  273.  
  274. #ifndef _STORRSRC_
  275. #include <StorRsrc.h>
  276. #endif
  277.  
  278. #ifndef _DLOGUTIL_
  279. #include <DlogUtil.h>
  280. #endif
  281.  
  282. #ifndef _BNDNSUTL_
  283. #include <BndNSUtl.h>
  284. #endif
  285.  
  286. #ifndef SOM_Module_Apple_defined
  287. #include <NoPart.xh>
  288. #endif
  289.  
  290. #ifndef _BINDINGUTILS_
  291. #include "BindingUtils.h"
  292. #endif
  293.  
  294. #ifndef _SCRIPTID_
  295. #include "ScriptID.h"
  296. #endif
  297.  
  298. #pragma segment CMDraft
  299.  
  300. //==============================================================================
  301. // Constants
  302. //==============================================================================
  303.  
  304. const ODType    kODVersionNamePrefix    = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:Bento Version Name";
  305. const ODPropertyName kODPropRootSU        = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:DraftRootStorageUnit";
  306. const ODType    kODStorageUnitType      = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Type:StorageUnit";
  307. const ODType    kODStorageUnit            = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:ObjectType:StorageUnit";
  308. const ODULong    kODInitialNumEntries = 8;
  309.  
  310. const corbastring kFrameClassName = "ODFrame";
  311.  
  312. #define    kMaxStringSize    32
  313. #define kInitialHashTableEntries 8
  314.  
  315. #define lazyOpen 1
  316.  
  317. // For debugging
  318.  
  319. #if ODDebug
  320. // #define ODDebug_Drafts    1
  321. // #define ODDebug_DebugRefCount 1
  322. // #define ODDebug_CMDraft 1
  323. // #define DebugClone 1
  324. // #define ODDebug_VersionList    1
  325. // #define ODDebug_CloningAnnotations 1
  326. // #define ODDebug_Unloading_Classes 1
  327. #endif
  328.  
  329. #ifdef DebugClone
  330. // somPrintf must be in the else clause so if stmt is complete [cc]
  331. #define PRINT_CLONE    if ( kODFalse ) ; else somPrintf
  332. #else
  333. #define PRINT_CLONE    if ( kODTrue ) ; else somPrintf
  334. #endif
  335.  
  336. //==============================================================================
  337. // Local Classes
  338. //==============================================================================
  339.  
  340. class SULink : public Link {
  341.  
  342. public:
  343.     
  344.     SULink(ODStorageUnitID fromID, ODStorageUnitID toID)
  345.     {
  346.         fFromID = fromID;
  347.         fToID = toID;
  348.     }
  349.     ~  SULink() {;};
  350.     
  351.     ODStorageUnitID    GetFromID() {return fFromID;};
  352.     ODStorageUnitID    GetToID() {return fToID;};
  353.  
  354. private:
  355.     
  356.     ODStorageUnitID                fFromID;
  357.     ODStorageUnitID                fToID;
  358. };
  359.  
  360. //==============================================================================
  361. // Function Prototypes
  362. //==============================================================================
  363.  
  364. static CMStorageUnit* NewCMStorageUnit(ODMemoryHeapID heapID);
  365.  
  366. static CMObject AcquireDraftPropertiesObject(CMContainer container);
  367. static ODType GetVersionNameFromVersionID(ODVersionID id, ODMemoryHeapID heapID);
  368.  
  369. static void SetOriginalDraft(Environment* ev, ODDraft* targetDraft, ODDraft* originalDraft);
  370. static ODDraft* GetOriginalDraft(Environment* ev, ODDraft* draft);
  371. static ODBoolean OriginalCloneKindExists(Environment* ev, ODDraft* draft);
  372. static void SetOriginalCloneKind(Environment* ev, ODDraft* targetDraft, ODCloneKind cloneKind);
  373.  
  374. static ODBoolean IsFrameObject(Environment* ev, ODDraft* draft, ODID objectID);
  375. static ODBoolean IsLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  376. static ODBoolean IsLinkSourceObject(Environment* ev, ODDraft* draft, ODID objectID);
  377. static ODBoolean IsEitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  378. static ODBoolean IsNeitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  379.  
  380. static void itoa(ODULong number, ODSByte* cstring);
  381.  
  382. static ODULong PurgeAllStorageUnits(Environment* ev, OpenHashTable* storageUnits, IDList* idList);
  383.  
  384. static void SetupForUpdatingDraft(Environment* ev,
  385.                                         CMDocument* localDoc,
  386.                                         ODVersionID prevVersionID,
  387.                                         CMValue version);            
  388.  
  389. static ODBoolean CheckPartAction(void* k, void* v, ODULong s, void* r);
  390.  
  391. static void CopyProperty(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU, ODPropertyName prop);
  392. static void CopyDraftAnnotations(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU);
  393. static void SetStorageUnitType(Environment* ev, ODDraftPermissions perms, ODStorageUnit* su, ODType suType);
  394. static ODISOStr GetStorageUnitType(Environment* ev, ODDraft* draft, ODID objectID);
  395. static ODID RootPartID(Environment* ev, ODDraft* draft);
  396.  
  397. // For debugging
  398.  
  399. #ifdef DebugStorage
  400.  
  401. #define MyDebugStr(s) do {somPrintf(s);} while (0)
  402. #define MyDebug2Str(f,p1,p2) do {somPrintf(f, p1, p2);} while (0)
  403.  
  404. #else
  405.  
  406. #define MyDebugStr(s)
  407. #define MyDebug2Str(f,p1,p2)
  408.  
  409. #endif
  410.  
  411. //==============================================================================
  412. // Static variables
  413. //==============================================================================
  414.  
  415. // Used by CheckPartAction
  416. static CMDraft*    sInterchangeDraft = kODNULL;
  417. static ODISOStr    sSUTypeBuffer;
  418. static ODID        sRootPartIDToIgnore;
  419.  
  420. //------------------------------------------------------------------------------
  421. // ReadClonedObjectTable
  422. //------------------------------------------------------------------------------
  423.  
  424. // These are private property and value for Bento Container Suite. 
  425. // They are used for data interchange. They enable multiple clones to the clipboard
  426. // and d&d container.
  427. const ODPropertyName    kODPropClonedObjectTable  = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:ClonedObjectTable";
  428. const ODValueType        kODTypeClonedObjectTable  = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Type:ClonedObjectTable";
  429.  
  430. ODStatic void ReadClonedObjectTable(Environment* ev, OpenHashTable* clonedSUIDs, ODDraft* destDraft)
  431. {
  432.     PRINT_CLONE("CMDraft: ReadClonedObjectTable\n");
  433.  
  434.     TempODStorageUnit su = destDraft->AcquireDraftProperties(ev);
  435.     if (ODSUExistsThenFocus(ev, su, kODPropClonedObjectTable, kODTypeClonedObjectTable) )
  436.     {
  437.         su->SetOffset(ev, 0);
  438.         
  439.         ODULong    size = su->GetSize(ev);
  440.         ODID    fromID;
  441.         ODID    toID;
  442.     
  443.         while ( su->GetOffset(ev) < size )
  444.         {
  445.             StorageUnitGetValue(su, ev, sizeof(ODULong), (ODValue) &fromID);
  446.             StorageUnitGetValue(su, ev, sizeof(ODULong), (ODValue) &toID);
  447.             PRINT_CLONE("    fromID %d, toID %d\n", fromID, toID);
  448.             clonedSUIDs->ReplaceEntry(&fromID, &toID);
  449.         }
  450.     }
  451. }
  452.  
  453. //------------------------------------------------------------------------------
  454. // WriteClonedObjectTable
  455. //------------------------------------------------------------------------------
  456.  
  457. ODStatic void WriteClonedObjectTable(Environment* ev, OpenHashTable* clonedSUIDs, ODDraft* destDraft)
  458. {
  459.     PRINT_CLONE("CMDraft: WriteClonedObjectTable\n");
  460.  
  461.     TempODStorageUnit su = destDraft->AcquireDraftProperties(ev);
  462.         
  463.     ODSUForceFocus(ev, su, kODPropClonedObjectTable, kODTypeClonedObjectTable);
  464.     
  465.     su->SetOffset(ev, 0);
  466.  
  467.     ODULong    oldSize = su->GetSize(ev);
  468.  
  469.     ODID        fromID;
  470.     ODID        toID;
  471.  
  472.     OpenHashTableIterator iter(clonedSUIDs);
  473.     for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID))
  474.     {
  475.         PRINT_CLONE("    from ID %d to ID %d\n", fromID, toID);
  476.         StorageUnitSetValue(su, ev, sizeof(ODULong), (ODValue) &fromID);
  477.         StorageUnitSetValue(su, ev, sizeof(ODULong), (ODValue) &toID);
  478.     }
  479.  
  480.     ODULong    newSize = su->GetOffset(ev);
  481.     if ( oldSize > newSize )
  482.         su->DeleteValue(ev, oldSize - newSize);
  483. }
  484.  
  485. //==============================================================================
  486. // CMDraft
  487. //==============================================================================
  488.  
  489. //------------------------------------------------------------------------------
  490. // CMDraft: FailIfNotExclusiveWrite
  491. //------------------------------------------------------------------------------
  492.  
  493. SOM_Scope void  SOMLINK CMDraftFailIfNotExclusiveWrite(CMDraft *somSelf, Environment *ev)
  494. {
  495.     CMDraftData *somThis = CMDraftGetData(somSelf);
  496.     CMDraftMethodDebug("CMDraft","FailIfNotExclusiveWrite");
  497.  
  498.     if (_fPermissions != kODDPExclusiveWrite)
  499.          ODSetSOMException(ev,kODErrInvalidPermissions);
  500. }
  501.  
  502. //------------------------------------------------------------------------------
  503. // CMDraft: GetDocument
  504. //------------------------------------------------------------------------------
  505.  
  506. SOM_Scope ODDocument*  SOMLINK CMDraftGetDocument(CMDraft *somSelf, Environment *ev)
  507. {
  508.     CMDraftData *somThis = CMDraftGetData(somSelf);
  509.     CMDraftMethodDebug("CMDraft","GetDocument");
  510.  
  511.     return _fDocument;
  512. }
  513.  
  514. //------------------------------------------------------------------------------
  515. // CMDraft: GetID
  516. //------------------------------------------------------------------------------
  517.  
  518. SOM_Scope ODDraftID  SOMLINK CMDraftGetID(CMDraft *somSelf, Environment *ev)
  519. {
  520.     CMDraftData *somThis = CMDraftGetData(somSelf);
  521.     CMDraftMethodDebug("CMDraft","GetID");
  522.  
  523.     return _fID;
  524. }
  525.  
  526. //------------------------------------------------------------------------------
  527. // CMDraft: AcquireDraftProperties
  528. //------------------------------------------------------------------------------
  529.  
  530. SOM_Scope ODStorageUnit*  SOMLINK CMDraftAcquireDraftProperties(CMDraft *somSelf, Environment *ev)
  531. {
  532.     CMDraftData *somThis = CMDraftGetData(somSelf);
  533.     CMDraftMethodDebug("CMDraft","AcquireDraftProperties");
  534.  
  535.     SOM_TRY
  536.     
  537.     CMObject            draftPropertiesObject;
  538.     CMStorageUnit*        draftProperties;
  539.     ODStorageUnitID    id;
  540.     
  541.     if (_fDraftProperties != kODNULL) {
  542.         _fDraftProperties->Internalize(ev);
  543.     }
  544.     else {
  545.  
  546.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  547.         ODSessionMustHaveCMAllocReserve(cmContainer);
  548.         // AcquireDraftPropertiesObject() makes CM calls:
  549.  
  550.         draftPropertiesObject = AcquireDraftPropertiesObject(somSelf->GetCMContainer(ev));
  551.         if (draftPropertiesObject == kODNULL)
  552.             THROW(kODErrNoDraftProperties);
  553.         
  554.         id = _fIDList->Add(draftPropertiesObject);
  555.         draftProperties = NewCMStorageUnit(somSelf->GetHeap(ev));
  556.         draftProperties->InitStorageUnit(ev, somSelf, id);
  557.         _fStorageUnits->ReplaceEntry(&id, &draftProperties);
  558.         _fDraftProperties = draftProperties;
  559.         
  560.         ODSessionRestoreCMAllocReserve(cmContainer);
  561.     }
  562.     
  563.     _fDraftProperties->Acquire(ev);
  564.     return _fDraftProperties;
  565.  
  566.     SOM_CATCH_ALL
  567.     SOM_ENDTRY
  568.     return kODNULL;
  569. }
  570.  
  571. //------------------------------------------------------------------------------
  572. // CMDraft: Acquire
  573. //------------------------------------------------------------------------------
  574.  
  575. SOM_Scope void  SOMLINK CMDraftAcquire(CMDraft *somSelf, Environment *ev)
  576. {
  577. //  CMDraftData *somThis = CMDraftGetData(somSelf);
  578.     CMDraftMethodDebug("CMDraft","Acquire");
  579.  
  580.     SOM_TRY
  581.         parent_Acquire(somSelf, ev);
  582.     SOM_CATCH_ALL
  583.     SOM_ENDTRY
  584. }
  585.  
  586. //------------------------------------------------------------------------------
  587. // CMDraft: Release
  588. //------------------------------------------------------------------------------
  589.  
  590. SOM_Scope void  SOMLINK CMDraftRelease(CMDraft *somSelf, Environment *ev)
  591. {
  592.     CMDraftData *somThis = CMDraftGetData(somSelf);
  593.     CMDraftMethodDebug("CMDraft","Release");
  594.  
  595.     SOM_TRY
  596.     
  597.     parent_Release(somSelf, ev);
  598.     if (somSelf->GetRefCount(ev) == 0) {
  599.         if (_fDraftProperties != kODNULL) {
  600.             _fDraftProperties->Release(ev);
  601.             _fDraftProperties = kODNULL;
  602.         }
  603. //        WASSERTM((somSelf->AreEmptyCollections(ev) != kODFalse), "OutstandingObjects in CMDraft: Release.");
  604.         _fDocument->ReleaseDraft(ev, somSelf);
  605.     }
  606.     
  607.     SOM_CATCH_ALL
  608.     
  609.         ODError err = ErrorCode();
  610.  
  611.         WARN("Error occurred in ODContainer::Release: %d %s", err, ErrorMessage() ?ErrorMessage() :"");
  612.  
  613.         SetErrorCode(kODNoError);
  614.  
  615.     SOM_ENDTRY
  616. }
  617.  
  618. //------------------------------------------------------------------------------
  619. // CMDraft: GetPermissions
  620. //------------------------------------------------------------------------------
  621.  
  622. SOM_Scope ODDraftPermissions  SOMLINK CMDraftGetPermissions(CMDraft *somSelf, Environment *ev)
  623. {
  624.     CMDraftData *somThis = CMDraftGetData(somSelf);
  625.     CMDraftMethodDebug("CMDraft","GetPermissions");
  626.  
  627.     return _fPermissions;
  628. }
  629.  
  630. //------------------------------------------------------------------------------
  631. // CMDraft: CreateStorageUnit
  632. //------------------------------------------------------------------------------
  633.  
  634. SOM_Scope ODStorageUnit*  SOMLINK CMDraftCreateStorageUnit(CMDraft *somSelf, Environment *ev)
  635. {
  636.     CMDraftData *somThis = CMDraftGetData(somSelf);
  637.     CMDraftMethodDebug("CMDraft","CreateStorageUnit");
  638.  
  639.     ODStorageUnit*    su = kODNULL; ODVolatile(su);
  640.  
  641.     SOM_TRY
  642.  
  643.     somSelf->FailIfNotExclusiveWrite(ev);
  644.     
  645.     su = somSelf->CreateSU(ev, kODNULL, kODStorageUnit);
  646.     SetStorageUnitType(ev, _fPermissions, su, kODStorageUnit);
  647.  
  648.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  649.  
  650.     SOM_CATCH_ALL
  651.         if (su != kODNULL) {
  652.             TRY{
  653.                 somSelf->ReleaseStorageUnit(ev, su->GetID(ev));
  654.             }CATCH_ALL{
  655.                 // ignore exception
  656.             }ENDTRY
  657.             su = kODNULL;
  658.         }
  659.     SOM_ENDTRY
  660.     return su;
  661. }
  662.  
  663. //------------------------------------------------------------------------------
  664. // CMDraft: IsValidID
  665. //------------------------------------------------------------------------------
  666.  
  667. SOM_Scope ODBoolean  SOMLINK CMDraftIsValidID(CMDraft *somSelf, Environment *ev,
  668.         ODID id)
  669. {
  670.     CMDraftData *somThis = CMDraftGetData(somSelf);
  671.     CMDraftMethodDebug("CMDraft","IsValidID");
  672.  
  673.     SOM_TRY
  674.     
  675.     if ( id != kODNULLID )
  676.         return _fIDList->Exists(id);
  677.     
  678.     SOM_CATCH_ALL
  679.     SOM_ENDTRY
  680.     return kODFalse;
  681. }
  682.  
  683. //------------------------------------------------------------------------------
  684. // CMDraft: AcquireStorageUnit
  685. //------------------------------------------------------------------------------
  686.  
  687. SOM_Scope ODStorageUnit*  SOMLINK CMDraftAcquireStorageUnit(CMDraft *somSelf, Environment *ev,
  688.         ODStorageUnitID id)
  689. {
  690.     CMDraftData *somThis = CMDraftGetData(somSelf);
  691.     CMDraftMethodDebug("CMDraft","AcquireStorageUnit");
  692.  
  693.     SOM_TRY
  694.  
  695.     if (id == kODNULLID)
  696.         THROW(kODErrIllegalNullIDInput);
  697.  
  698.     ODStorageUnit*    su = kODNULL;
  699.     
  700.     if (_fStorageUnits->GetValue(&id, &su)) {
  701.         su->Acquire(ev);
  702.     }
  703.     else if ((_fIDList->Exists(id) == kODFalse) ||
  704.              (_fIDList->Get(id) != kODNULL)) {
  705.         su = somSelf->CreateSU(ev, id, kODStorageUnit);
  706.     }
  707.     return su;
  708.  
  709.     SOM_CATCH_ALL
  710.     SOM_ENDTRY
  711.     return kODNULL;
  712. }
  713.  
  714. //------------------------------------------------------------------------------
  715. // CMDraft: RemoveStorageUnit
  716. //------------------------------------------------------------------------------
  717.  
  718. SOM_Scope void  SOMLINK CMDraftRemoveStorageUnit(CMDraft *somSelf, Environment *ev,
  719.         ODStorageUnit* su)
  720. {
  721.     CMDraftData *somThis = CMDraftGetData(somSelf);
  722.     CMDraftMethodDebug("CMDraft","RemoveStorageUnit");
  723.  
  724.     SOM_TRY
  725.  
  726.     CMContainer cmContainer = somSelf->GetCMContainer(ev);
  727.     ODSessionMustHaveCMAllocReserve(cmContainer);
  728.     
  729.     ODID            id;
  730.     CMObject        object;
  731.     ODStorageUnit*    draftProperties;
  732.  
  733.     somSelf->FailIfNotExclusiveWrite(ev);
  734.     
  735.     draftProperties = somSelf->AcquireDraftProperties(ev);
  736.     if (su == draftProperties) {
  737.         draftProperties->Release(ev);
  738.         THROW(kODErrIllegalOperationOnSU);
  739.     }
  740.     else
  741.         draftProperties->Release(ev);
  742.         
  743.     // Get Storage Unit ID
  744.     
  745.     id = su->GetID(ev);
  746.     if (id == kODNULL)
  747.         THROW(kODErrInvalidStorageUnit);
  748.         
  749.     // Release the storage unit
  750.     su->Release(ev);
  751.     
  752.     // Remove Storage Unit from outstanding SU collection
  753.     
  754.     _fStorageUnits->RemoveEntry(&id);
  755.     
  756.     // Get and delete the CMObject associated with su.
  757.     
  758.     object = (CMObject) _fIDList->Get(id);
  759.     
  760.     // Remove the entry in the ID-object collection.
  761.     
  762.     _fIDList->Remove(id);
  763.     
  764.     // Delete the object
  765.     
  766.     if (object != kODNULL)
  767.         CMDeleteObject(object);
  768.     
  769.     // Destroy su
  770.     
  771.     delete su;
  772.     
  773.     // Mark this draft dirty
  774.     
  775.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  776.  
  777.     ODSessionRestoreCMAllocReserve(cmContainer);
  778.  
  779.     SOM_CATCH_ALL
  780.     SOM_ENDTRY
  781. }
  782.  
  783. //------------------------------------------------------------------------------
  784. // CMDraft: ChangedFromPrev
  785. //------------------------------------------------------------------------------
  786.  
  787. SOM_Scope ODBoolean  SOMLINK CMDraftChangedFromPrev(CMDraft *somSelf, Environment *ev)
  788. {
  789.     CMDraftData *somThis = CMDraftGetData(somSelf);
  790.     CMDraftMethodDebug("CMDraft","ChangedFromPrev");
  791.     
  792.     SOM_TRY
  793.  
  794.     ODBoolean        changedFromPrev;
  795.     VersionList*    versionList = kODNULL;
  796.     
  797.     versionList = _fDocument->TestAndGetVersionList(ev);
  798.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  799.     
  800.     TRY
  801.         changedFromPrev = somSelf->IsChangedFromPrev(ev, versionList);
  802.         
  803.     CATCH_ALL
  804.     
  805.         _fDocument->ReleaseVersionList(ev);
  806.         RERAISE;
  807.         
  808.     ENDTRY
  809.     
  810.     _fDocument->ReleaseVersionList(ev);
  811.     
  812.     return changedFromPrev;
  813.  
  814.     SOM_CATCH_ALL
  815.     SOM_ENDTRY
  816.     return kODFalse;
  817. }
  818.  
  819. //------------------------------------------------------------------------------
  820. // CMDraft: SetChangedFromPrev
  821. //------------------------------------------------------------------------------
  822.  
  823. SOM_Scope void  SOMLINK CMDraftSetChangedFromPrev(CMDraft *somSelf, Environment *ev)
  824. {
  825.     CMDraftData *somThis = CMDraftGetData(somSelf);
  826.     CMDraftMethodDebug("CMDraft","SetChangedFromPrev");
  827.  
  828.     SOM_TRY
  829.     
  830.     somSelf->FailIfNotExclusiveWrite(ev);
  831.  
  832.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  833.  
  834.     SOM_CATCH_ALL
  835.     SOM_ENDTRY
  836. }
  837.  
  838. //------------------------------------------------------------------------------
  839. // CMDraft: RemoveFromDocument
  840. //------------------------------------------------------------------------------
  841.  
  842. SOM_Scope void  SOMLINK CMDraftRemoveFromDocument(CMDraft *somSelf, Environment *ev)
  843. {
  844.     CMDraftData *somThis = CMDraftGetData(somSelf);
  845.     CMDraftMethodDebug("CMDraft","RemoveFromDocument");
  846.  
  847.     SOM_TRY
  848.     
  849.     _fDocument->CollapseDrafts(ev, somSelf, kODNULL);
  850.  
  851.     SOM_CATCH_ALL
  852.     SOM_ENDTRY
  853. }
  854.  
  855. //------------------------------------------------------------------------------
  856. // CMDraft: RemoveChanges
  857. //------------------------------------------------------------------------------
  858.  
  859. SOM_Scope ODDraft*  SOMLINK CMDraftRemoveChanges(CMDraft *somSelf, Environment *ev)
  860. {
  861.     CMDraftData *somThis = CMDraftGetData(somSelf);
  862.     CMDraftMethodDebug("CMDraft","RemoveChanges");
  863.     
  864.     SOM_TRY
  865.     
  866.     VersionList*    versionList = kODNULL;
  867.     
  868.     somSelf->FailIfNotExclusiveWrite(ev);
  869.     
  870.     if (_fDraftProperties != kODNULL) {
  871.         _fDraftProperties->Release(ev);
  872.         _fDraftProperties = kODNULL;
  873.     }
  874.     
  875. //    WASSERTM((somSelf->AreEmptyCollections(ev) != kODFalse), "OutstandingObjects in CMDraft: RemoveChanges.");
  876.     
  877.     somSelf->DestroyVersion(ev);
  878.     
  879.     versionList = _fDocument->TestAndGetVersionList(ev);
  880.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  881.  
  882. #ifdef ODDebug_VersionList
  883.     _fDocument->GetVersionList(ev)->Print(">>> Entering RemoveChanges");
  884. #endif
  885.  
  886.     TRY
  887.         if (versionList->Exists(_fID) != kODFalse)
  888.             versionList->RemoveChanges(_fID);
  889.         
  890.     CATCH_ALL
  891.     
  892.         _fDocument->ReleaseVersionList(ev);
  893.         RERAISE;
  894.  
  895.     ENDTRY
  896.  
  897. #if !TestFlushContainer
  898.     _fDocument->ExternalizeVersionList(ev, kODFalse);
  899. #endif
  900.     _fDocument->ReleaseVersionList(ev);
  901.         
  902.     somSelf->Open(ev);
  903.     
  904.     somSelf->SetChangedFromPrevFlag(ev, kODFalse);
  905.  
  906. #ifdef ODDebug_VersionList
  907.     _fDocument->GetVersionList(ev)->Print(">>> Exiting RemoveChanges");
  908. #endif
  909.  
  910.     return somSelf;
  911.  
  912.     SOM_CATCH_ALL
  913.     SOM_ENDTRY
  914.     return somSelf;
  915. }
  916.  
  917. //------------------------------------------------------------------------------
  918. // CMDraft: Externalize
  919. //------------------------------------------------------------------------------
  920.  
  921. SOM_Scope ODDraft*  SOMLINK CMDraftExternalize(CMDraft *somSelf, Environment *ev)
  922. {
  923.     CMDraftData *somThis = CMDraftGetData(somSelf);
  924.     CMDraftMethodDebug("CMDraft","Externalize");
  925.  
  926.     SOM_TRY
  927.     
  928.     if ( _fScriptingIDMgr )
  929.         _fScriptingIDMgr->Save(ev);    // May add a storage unit! [cc]
  930.     
  931.     somSelf->ExternalizeCollections(ev);
  932.  
  933.     _fExternalized = kODTrue;
  934.         
  935.     // DO THE ACTUAL EXTERNALIZATION HERE
  936.     
  937.     somSelf->FlushVersion(ev);
  938.     
  939.     return somSelf;
  940.  
  941.     SOM_CATCH_ALL
  942.     SOM_ENDTRY
  943.     return somSelf;
  944. }
  945.  
  946. //------------------------------------------------------------------------------
  947. // CMDraft: SaveToAPrevious
  948. //------------------------------------------------------------------------------
  949.  
  950. SOM_Scope ODDraft*  SOMLINK CMDraftSaveToAPrevious(CMDraft *somSelf, Environment *ev,
  951.         ODDraft* to)
  952. {
  953.     CMDraftData *somThis = CMDraftGetData(somSelf);
  954.     CMDraftMethodDebug("CMDraft","SaveToAPrevious");
  955.  
  956.     SOM_TRY
  957.  
  958.     _fDocument->SaveToAPrevDraft(ev, somSelf, to);
  959.     return somSelf;
  960.  
  961.     SOM_CATCH_ALL
  962.     SOM_ENDTRY
  963.     return somSelf;
  964. }
  965.  
  966. //------------------------------------------------------------------------------
  967. // CMDraft: CreateFrame
  968. //------------------------------------------------------------------------------
  969.  
  970. SOM_Scope ODFrame*  SOMLINK CMDraftCreateFrame(CMDraft *somSelf, Environment *ev,
  971.         ODObjectType        frameType,
  972.         ODFrame*    containingFrame,
  973.         ODShape*     frameShape,
  974.         ODCanvas*    biasCanvas,
  975.         ODPart*         part,
  976.         ODTypeToken    viewType,
  977.         ODTypeToken    presentation,
  978.         ODBoolean        isSubframe,
  979.         ODBoolean         isOverlaid)
  980. {
  981.     CMDraftData *somThis = CMDraftGetData(somSelf);
  982.     CMDraftMethodDebug("CMDraft","CreateFrame");
  983.  
  984.     ODStorageUnit*        su = kODNULL;
  985.     ODFrame*            frame = kODNULL;
  986.     ODStorageUnitID        id = kODNULLID;
  987.  
  988.     ODVolatile(su);
  989.     ODVolatile(frame);
  990.     ODVolatile(id);
  991.  
  992.     SOM_TRY
  993.  
  994.         if (ODISOStrEqual(frameType, kODFrameObject) != kODFalse)    
  995.             somSelf->FailIfNotExclusiveWrite(ev);
  996.  
  997.         frame = new ODFrame();
  998.         if (frame == kODNULL)
  999.             THROW(kODErrCannotCreateFrame);
  1000.         
  1001.          if (ODISOStrEqual(frameType, kODFrameObject) != kODFalse) {
  1002.             su = somSelf->CreateSU(ev, kODNULL, kODFrameObject);
  1003.             SetStorageUnitType(ev, _fPermissions, su, kODFrameObject);
  1004.             id = su->GetID(ev);
  1005.             _fPersistentObjects->ReplaceEntry(&id, &frame);
  1006.             frame->InitFrame(ev, su, containingFrame, frameShape, biasCanvas, part,
  1007.                              viewType, presentation, isSubframe, isOverlaid);
  1008.             somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1009.         }
  1010.         else if (ODISOStrEqual(frameType, kODNonPersistentFrameObject) != kODFalse) {
  1011.             id = _fIDList->Add(kODNULL);
  1012.             _fPersistentObjects->ReplaceEntry(&id, &frame);
  1013.             frame->InitFrameNonPersistent(ev, somSelf, id, containingFrame, frameShape,
  1014.                         biasCanvas, part, viewType, presentation, isSubframe, isOverlaid);
  1015.         }
  1016.         else
  1017.             THROW(kODErrInvalidObjectType);
  1018.  
  1019.     
  1020.     SOM_CATCH_ALL
  1021.         if (frame != kODNULL) {
  1022.             TRY{
  1023.                 if (id != kODNULLID)
  1024.                 {
  1025.                     if (su == kODNULL)
  1026.                     {
  1027.                         // This is just for non-persistent frame.
  1028.                         // Every other real persistent object should use RemovePersistentObject.
  1029.                         ODReleaseObject(ev, frame);
  1030.                         _fPersistentObjects->RemoveEntry(&id);
  1031.                     }
  1032.                     else
  1033.                         somSelf->RemovePersistentObject(ev, frame);
  1034.                 }
  1035.                 else {
  1036.                     delete frame;
  1037.                     if (su != kODNULL)
  1038.                         somSelf->RemoveStorageUnit(ev, su);
  1039.                 }
  1040.             }CATCH_ALL{
  1041.                 // ignore exception
  1042.             }ENDTRY
  1043.             frame = kODNULL;
  1044.         }
  1045.     SOM_ENDTRY
  1046.         
  1047.     return frame;
  1048. }
  1049.  
  1050. //------------------------------------------------------------------------------
  1051. // CMDraft: AcquireFrame
  1052. //------------------------------------------------------------------------------
  1053.  
  1054. SOM_Scope ODFrame*  SOMLINK CMDraftAcquireFrame(CMDraft *somSelf, Environment *ev,
  1055.         ODStorageUnitID id)
  1056. {
  1057.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1058.     CMDraftMethodDebug("CMDraft","AcquireFrame");
  1059.  
  1060.     ODStorageUnit*    su = kODNULL; ODVolatile(su);
  1061.     ODFrame*        frame = kODNULL; ODVolatile(frame);
  1062.  
  1063.     SOM_TRY
  1064.  
  1065.     if (id == kODNULLID)
  1066.         THROW(kODErrIllegalNullIDInput);
  1067.         
  1068.     frame = (ODFrame*) somSelf->RetrievePersistentObject(ev, id);
  1069.     
  1070.     if (frame == kODNULL) {    
  1071.         
  1072.         su = somSelf->AcquireStorageUnit(ev, id);
  1073.         frame = new ODFrame();
  1074.         
  1075.         if (frame == kODNULL)
  1076.             THROW(kODErrCannotAcquireFrame);
  1077.  
  1078.         // A better way to do this is to let ODFrame::InitFrameFromStorage or
  1079.         // ODPersistentObject::InitPersistentObjectFromStorage to increment the
  1080.         // refcount. In that way, we can always release su here (or even better
  1081.         // make su into a temp obj. - VL        
  1082.         _fPersistentObjects->ReplaceEntry(&id, &frame);
  1083.         frame->InitFrameFromStorage(ev, su);
  1084.         
  1085.         ODStorageUnit *su2 = su;
  1086.         su = kODNULL;                                    // frame owns reference now
  1087.         
  1088.         SetStorageUnitType(ev, _fPermissions, su2, kODFrameObject);
  1089.     }
  1090.     
  1091.     SOM_CATCH_ALL
  1092.         ODSafeReleaseObject(su);
  1093.         if( frame ) WASSERT(frame->GetRefCount(ev)==1);
  1094.         ODSafeReleaseObject(frame);
  1095.     SOM_ENDTRY
  1096.     
  1097.     return frame;
  1098. }
  1099.  
  1100. //------------------------------------------------------------------------------
  1101. // CMDraft: ReleaseFrame
  1102. //------------------------------------------------------------------------------
  1103.  
  1104. SOM_Scope void  SOMLINK CMDraftReleaseFrame(CMDraft *somSelf, Environment *ev,
  1105.         ODFrame* frame)
  1106. {
  1107.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1108.     CMDraftMethodDebug("CMDraft","ReleaseFrame");
  1109.  
  1110.     SOM_TRY
  1111.  
  1112.     somSelf->ReleasePersistentObject(ev, frame);
  1113.  
  1114.     SOM_CATCH_ALL
  1115.     SOM_ENDTRY
  1116. }
  1117.  
  1118. //------------------------------------------------------------------------------
  1119. // CMDraft: RemoveFrame
  1120. //------------------------------------------------------------------------------
  1121.  
  1122. SOM_Scope void  SOMLINK CMDraftRemoveFrame(CMDraft *somSelf, Environment *ev,
  1123.         ODFrame* frame)
  1124. {
  1125.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1126.     CMDraftMethodDebug("CMDraft","RemoveFrame");
  1127.  
  1128.     SOM_TRY
  1129.  
  1130.     somSelf->FailIfNotExclusiveWrite(ev);
  1131.     
  1132.     if (frame->GetStorageUnit(ev) == kODNULL)
  1133.     {
  1134.         frame->Release(ev);
  1135.     }
  1136.     else
  1137.     {
  1138.         // ODFrame should call DropPersistentObjectID in its Remove method;
  1139.         // for efficiency its not called again here. Even though this
  1140.         // method should be called before a draft is saved to prevent
  1141.         // saving a removed frame, there is  code in the implementation of 
  1142.         // ODFrame::Externalize to deal with a frame that has had its Remove 
  1143.         // method called, but whose refcount has not gone to zero.
  1144.         // Rather than rely on this method being called before the document 
  1145.         // is saved, let ODFrame call DropPersistentObjectID. [cc]
  1146.         somSelf->RemovePersistentObject(ev, frame);
  1147.     }
  1148.  
  1149.     SOM_CATCH_ALL
  1150.     SOM_ENDTRY
  1151. }
  1152.  
  1153. //------------------------------------------------------------------------------
  1154. // CMDraft: ConstructRealPart
  1155. //------------------------------------------------------------------------------
  1156.  
  1157. SOM_Scope ODPart*  SOMLINK CMDraftConstructRealPart(CMDraft *somSelf, Environment *ev,
  1158.         ODStorageUnit* su, ODBoolean isInitPartFromStorage,
  1159.         ODPartWrapper* partWrapper,
  1160.         ODType partType, ODEditor theEditor)
  1161. {
  1162.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1163.     CMDraftMethodDebug("CMDraft","ConstructRealPart");
  1164.  
  1165.     ODPart* part = kODNULL;    ODVolatile(part);
  1166.     ODEditor editorForPart = kODNULL;
  1167.     
  1168.     SOM_TRY
  1169.  
  1170.         ODSession*            session = (ODSession*) _fDocument->GetContainer(ev)->GetStorageSystem(ev)->GetSession(ev);
  1171.         ODBinding*            binding = session->GetBinding(ev);
  1172.         ODBoolean            useSpecifiedEditor = kODFalse; ODVolatile(useSpecifiedEditor);
  1173.         ODBoolean            degradeToNoPart = kODFalse; ODVolatile(degradeToNoPart);
  1174.         ODError                partLoadErr = noErr;
  1175.         Str255                partLoadErrStr = "\p";
  1176.         
  1177.         if (theEditor == kODNULL)
  1178.             editorForPart = binding->ChooseEditorForPart(ev, su, partType);
  1179.         else
  1180.         {
  1181.             // if a specific editor is passed in then we should use it
  1182.             // and never substitue it by another editor, including NoPart
  1183.             useSpecifiedEditor = kODTrue;
  1184.             editorForPart = theEditor;
  1185.             if ((_fPermissions != kODDPReadOnly) && !ODISOStrEqual(editorForPart, kODBlackBoxHandlerOfLastResort))
  1186.             {
  1187.                 //ODSetISOStrProp(ev, su, kODPropPreferredEditor, kODEditor, editorForPart);
  1188.                 
  1189.                 // Preferred editor properties must be updated atomically. 
  1190.                 ODSetPreferredEditorProps(su,editorForPart);
  1191.             }
  1192.         }
  1193.     
  1194.         do {
  1195.         //    if (degradeToNoPart) {    
  1196.         //        partWrapper->SetRealPart(ev, part, kODBlackBoxHandlerOfLastResort);
  1197.                 /* Don't display alert now, set NoPart message instead:
  1198.                 ODIText* editorUserString = kODNULL;
  1199.                 Str255     editorString = "\p";
  1200.                 GetUserEditorFromEditor( session->GetNameSpaceManager(ev), editorForPart, &editorUserString );
  1201.                 TempODIText tempEditorUserString = editorUserString; // ensure it's deleted
  1202.                 GetITextPString( editorUserString, editorString );
  1203.                 ParamText(editorString, "\p", "\p", "\p");
  1204.                 (void) ShowAlert(ev, kODAlertCannotLoadPartError, kODNULL, session);
  1205.                 */
  1206.         //    }
  1207.  
  1208.             ODBoolean editorIsNoPart = ODISOStrEqual(editorForPart, kODBlackBoxHandlerOfLastResort);
  1209.             if (degradeToNoPart || editorIsNoPart)
  1210.             {
  1211.                 part = binding->ConstructNoPart(ev);
  1212.                 if (!useSpecifiedEditor) 
  1213.                 {
  1214.                     // Set message in part to explain to user why it appeared:
  1215.                     ODError err; ODVolatile(err);
  1216.                     ODIText *editorName = kODNULL; ODVolatile(editorName);
  1217.                     
  1218.                     if( degradeToNoPart ) 
  1219.                     {                                        // Reason 1: Error loading part
  1220.                         err = partLoadErr;
  1221.                         
  1222.                         if (!GetUserEditorFromEditor( session->GetNameSpaceManager(ev), editorForPart, &editorName )) 
  1223.                             editorName = CreateIText(smRoman,langEnglish,theEditor); // SOM classnames are always Roman...
  1224.                     }
  1225.                     else 
  1226.                     {
  1227.                         err = 0;                            // Reason 2: Couldn't find part editor
  1228.                         
  1229.                         ODULong size;
  1230.                         TempODEditor editor = ODGetISOStrProp(ev, su, 
  1231.                                             kODPropPreferredEditor, kODEditor, kODNULL, &size);
  1232.                         if( editor && !ODISOStrEqual(editor,kODBlackBoxHandlerOfLastResort) )
  1233.                         {
  1234.                             // See if there is an editor for other CPU, if there is one we report fragArchError
  1235.                             TRY
  1236.                                 ODNameSpace* unusableNameSpace = 
  1237.                                     (session->GetNameSpaceManager(ev)->HasNameSpace( ev, kODWrongCUPEditor));
  1238.                                 if ( unusableNameSpace && unusableNameSpace->Exists(ev, editor) ) {
  1239.                                     err = fragArchError;
  1240.                                     // We can get the user string of the editor
  1241.                                     ValueNameSpaceGetODName((ODValueNameSpace*)unusableNameSpace, ev, editor, &editorName );
  1242.                                 }
  1243.                             CATCH_ALL
  1244.                             ENDTRY
  1245.                         }
  1246.                         
  1247.                         if(!editorName)
  1248.                         {
  1249.                             TRY
  1250.                             editorName = ODGetITextProp(ev, su,
  1251.                                                 kODPropPreferredEditorUserString, kODMacIText, kODNULL);
  1252.                             CATCH_ALL
  1253.                                 WARN("Error getting kODPropPreferredEditorUserString");
  1254.                             ENDTRY
  1255.                         }
  1256.                         
  1257.                         if(!editorName)
  1258.                         {
  1259.                             LOG("Could not find a kODPropPreferredEditorUserString string");
  1260.  
  1261.                             // We are forced to use the SOM ID which is better than nothing...
  1262.                             ODULong size;
  1263.                             TempODEditor editor = ODGetISOStrProp(ev, su, 
  1264.                                                 kODPropPreferredEditor, kODEditor, kODNULL, &size);
  1265.                             if( editor )
  1266.                                 editorName = CreateIText(smRoman,langEnglish,editor);    // SOM classnames are always Roman...
  1267.                                 
  1268.                             WASSERT(!ODISOStrEqual(editor,kODBlackBoxHandlerOfLastResort));
  1269.                         }
  1270.                     }
  1271.                     CAST(part,Apple_NoPart)->SetUserMessage(ev, err,editorName,p2cstr(partLoadErrStr));
  1272.                 }
  1273.             } else {
  1274.                 // try to construct a part, if it fails then construct a NoPart instead
  1275.                 TRY
  1276.                     part = (ODPart*) ODNewObject(editorForPart,partLoadErrStr);
  1277.                 CATCH_ALL
  1278.                     if (useSpecifiedEditor)
  1279.                         RERAISE;
  1280.                     partLoadErr = ErrorCode();
  1281.                     degradeToNoPart = kODTrue;
  1282.                     continue;
  1283.                 ENDTRY
  1284.             }
  1285.         
  1286.             if (part == kODNULL)
  1287.                 THROW(kODErrCannotCreatePart);
  1288.             
  1289.             if (degradeToNoPart) {    
  1290.                 partWrapper->SetRealPart(ev, part, kODBlackBoxHandlerOfLastResort);
  1291.             } else
  1292.                 partWrapper->SetRealPart(ev, part, editorForPart);
  1293.         
  1294.             ODID id = su->GetID(ev);
  1295.             _fPersistentObjects->ReplaceEntry(&id, &partWrapper);
  1296.             
  1297.             su->Acquire(ev);                                 //This new reference belongs to the part
  1298.             
  1299.             TRY
  1300.                 if (isInitPartFromStorage)
  1301.                     partWrapper->InitPartFromStorage(ev, su, partWrapper);
  1302.                 else
  1303.                     partWrapper->InitPart(ev, su, partWrapper);
  1304.             CATCH_ALL
  1305. //                if ( ErrorCode() != memFullErr && ErrorCode()!=kODErrOutOfMemory )    
  1306. //                    RERAISE;
  1307.                 // not enough memory to Init, treat as can't load part
  1308.                 if (part) {
  1309.                     part->Release(ev);    // ReleaseRealPart expect ref count 0
  1310.                     somSelf->ReleaseRealPart(ev, part);
  1311.                     part = kODNULL;    
  1312.                 }
  1313.                 if (degradeToNoPart || useSpecifiedEditor)
  1314.                     RERAISE;
  1315.                 degradeToNoPart = kODTrue;
  1316.                 partLoadErr = ErrorCode();
  1317.             ENDTRY
  1318.         } while (degradeToNoPart && (part == kODNULL));
  1319.     
  1320.     SOM_CATCH_ALL
  1321.     
  1322.         part = kODNULL;
  1323.  
  1324.         if( ErrorCode() == kODErrCantLoadSOMClass )
  1325.             SetErrorCode(kODErrCannotCreatePart);        // Map to more specific error
  1326.  
  1327.     SOM_ENDTRY    
  1328.     
  1329.     if (editorForPart != theEditor)
  1330.         ODDisposePtr(editorForPart);
  1331.     
  1332.     return part;
  1333. }
  1334.  
  1335. //------------------------------------------------------------------------------
  1336. // CMDraft: ReleaseRealPart
  1337. //------------------------------------------------------------------------------
  1338.  
  1339. SOM_Scope void  SOMLINK CMDraftReleaseRealPart(CMDraft *somSelf, Environment *ev,
  1340.                                                 ODPart* realPart)
  1341. {
  1342.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1343.     CMDraftMethodDebug("CMDraft","ReleaseRealPart");
  1344.  
  1345.     SOM_TRY
  1346.     
  1347.     if (realPart == kODNULL)
  1348.         THROW(kODErrIllegalNullPartInput);
  1349.  
  1350.     if (realPart->GetRefCount(ev) != 0)
  1351.         THROW(kODErrRefCountGreaterThanZero);
  1352.     
  1353.     realPart->ReleaseAll(ev);
  1354.         
  1355.     delete realPart;
  1356.  
  1357.     SOM_CATCH_ALL
  1358.     SOM_ENDTRY
  1359. }
  1360.  
  1361. //------------------------------------------------------------------------------
  1362. // CMDraft: DeleteRealPart
  1363. //------------------------------------------------------------------------------
  1364.  
  1365. SOM_Scope void  SOMLINK CMDraftDeleteRealPart(CMDraft *somSelf, Environment *ev,
  1366.                                                 ODPart* realPart)
  1367. {
  1368.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1369.     CMDraftMethodDebug("CMDraft","DeleteRealPart");
  1370.  
  1371.     SOM_TRY
  1372.     
  1373.     if (realPart == kODNULL)
  1374.         THROW(kODErrIllegalNullPartInput);
  1375.  
  1376.     delete realPart;
  1377.  
  1378.     SOM_CATCH_ALL
  1379.     SOM_ENDTRY
  1380. }
  1381.  
  1382. //------------------------------------------------------------------------------
  1383. // CMDraft: CreatePart
  1384. //------------------------------------------------------------------------------
  1385.  
  1386. SOM_Scope ODPart*  SOMLINK CMDraftCreatePart(CMDraft *somSelf, Environment *ev,
  1387.         ODType partType, ODEditor optionalEditor)
  1388. {
  1389.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1390.     CMDraftMethodDebug("CMDraft","CreatePart");
  1391.  
  1392.     
  1393.     ODPartWrapper* partWrapper = kODNULL;
  1394.     
  1395.     ODVolatile(partWrapper);
  1396.     SOM_TRY
  1397.     
  1398.         somSelf->FailIfNotExclusiveWrite(ev);
  1399.     
  1400.         TempODStorageUnit su = somSelf->CreateSU(ev, kODNULL, kODPartObject);
  1401.     
  1402.         SetStorageUnitType(ev, _fPermissions, su, kODPartObject);
  1403.         
  1404.         if ( partType != kODNULL )
  1405.         {
  1406.             ODSetISOStrProp(ev, su, kODPropPreferredKind, kODISOStr, partType);
  1407.         }
  1408.     
  1409.         partWrapper = new ODPartWrapper;
  1410.         THROW_IF_NULL(partWrapper, kODErrOutOfMemory);
  1411.         partWrapper->InitPartWrapper(ev);
  1412.         
  1413.         somSelf->ConstructRealPart(ev, su, kODFalse, partWrapper, partType, optionalEditor);
  1414.     
  1415.         somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1416.         
  1417.     SOM_CATCH_ALL
  1418.     
  1419.         ODSafeReleaseObject(partWrapper);
  1420.         partWrapper = kODNULL;
  1421.         
  1422.     SOM_ENDTRY
  1423.  
  1424.     return partWrapper;
  1425. }
  1426.  
  1427. //------------------------------------------------------------------------------
  1428. // CMDraft: AcquirePart
  1429. //------------------------------------------------------------------------------
  1430.  
  1431. SOM_Scope ODPart*  SOMLINK CMDraftAcquirePart(CMDraft *somSelf, Environment *ev,
  1432.         ODStorageUnitID id)
  1433. {
  1434.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1435.     CMDraftMethodDebug("CMDraft","AcquirePart");
  1436.  
  1437.     ODPart* part = kODNULL;
  1438.     ODPartWrapper* partWrapper = kODNULL;
  1439.     
  1440.     ODVolatile(partWrapper);
  1441.     SOM_TRY
  1442.     
  1443.         if (id == kODNULLID)
  1444.             THROW(kODErrIllegalNullIDInput);
  1445.     
  1446.         part = (ODPart*) somSelf->RetrievePersistentObject(ev, id);
  1447.         if (part == kODNULL) {
  1448.             ODStorageUnit*    su = kODNULL;
  1449.             
  1450.             if (_fStorageUnits->GetValue(&id, &su) != kODFalse)
  1451.                 su->Acquire(ev);
  1452.             else 
  1453.                 su = somSelf->CreateSU(ev, id, kODPartObject);
  1454.             TempODStorageUnit tempSU = su; // ensure it's released
  1455.     
  1456.             partWrapper = new ODPartWrapper;
  1457.             THROW_IF_NULL(partWrapper, kODErrOutOfMemory);
  1458.             partWrapper->InitPartWrapper(ev);
  1459.             
  1460.             somSelf->ConstructRealPart(ev, su, kODTrue, partWrapper, kODNULL,  kODNULL);
  1461.     
  1462.             part = partWrapper;
  1463.     
  1464.             // If this storage unit was cloned from a content storage unit, its
  1465.             // storage unit type may be a plain storage unit.  When embedding
  1466.             // a content storage unit, this method will be called so we can
  1467.             // correct the property here. [cc]
  1468.             SetStorageUnitType(ev, _fPermissions, su, kODPartObject);
  1469.         }
  1470.     
  1471.     SOM_CATCH_ALL
  1472.         
  1473.         ODSafeReleaseObject(partWrapper);
  1474.         part = kODNULL;
  1475.         
  1476.     SOM_ENDTRY
  1477.     
  1478.     return part;
  1479. }
  1480.  
  1481. //------------------------------------------------------------------------------
  1482. // CMDraft: ReleasePart
  1483. //------------------------------------------------------------------------------
  1484.  
  1485. SOM_Scope void  SOMLINK CMDraftReleasePart(CMDraft *somSelf, Environment *ev,
  1486.         ODPart* part)
  1487. {
  1488.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1489.     CMDraftMethodDebug("CMDraft","ReleasePart");
  1490.  
  1491.     SOM_TRY
  1492.  
  1493.     somSelf->ReleasePersistentObject(ev, part);
  1494.  
  1495.     SOM_CATCH_ALL
  1496.     SOM_ENDTRY
  1497. }
  1498.  
  1499. //------------------------------------------------------------------------------
  1500. // CMDraft: RemovePart
  1501. //------------------------------------------------------------------------------
  1502.  
  1503. SOM_Scope void  SOMLINK CMDraftRemovePart(CMDraft *somSelf, Environment *ev,
  1504.         ODPart* part)
  1505. {
  1506.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1507.     CMDraftMethodDebug("CMDraft","RemovePart");
  1508.  
  1509.     SOM_TRY
  1510.  
  1511.     somSelf->DropPersistentObjectID(ev, part);
  1512.     somSelf->RemovePersistentObject(ev, part);
  1513.  
  1514.     SOM_CATCH_ALL
  1515.     SOM_ENDTRY
  1516. }
  1517.  
  1518. //------------------------------------------------------------------------------
  1519. // CMDraft: CreateLinkSpec
  1520. //------------------------------------------------------------------------------
  1521.  
  1522. SOM_Scope ODLinkSpec*  SOMLINK CMDraftCreateLinkSpec (CMDraft *somSelf, Environment *ev,
  1523.         ODPart* part,
  1524.         ODByteArray* data)
  1525. {
  1526.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1527.     CMDraftMethodDebug("CMDraft","CreateLinkSpec");
  1528.  
  1529.     ODLinkSpec* ls = kODNULL;
  1530.     
  1531.     ODVolatile(ls);
  1532.     SOM_TRY
  1533.         ls = new ODLinkSpec;
  1534.         THROW_IF_NULL(ls, kODErrOutOfMemory);
  1535.         ls->InitLinkSpec(ev, part, data);
  1536.     SOM_CATCH_ALL
  1537.         ODDeleteObject(ls);
  1538.     SOM_ENDTRY
  1539.         
  1540.     return ls;
  1541. }
  1542.  
  1543. //------------------------------------------------------------------------------
  1544. // CMDraft: CreateLinkSource
  1545. //------------------------------------------------------------------------------
  1546.  
  1547. SOM_Scope ODLinkSource*  SOMLINK CMDraftCreateLinkSource(CMDraft *somSelf, Environment *ev,
  1548.         ODPart* part)
  1549. {
  1550.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1551.     CMDraftMethodDebug("CMDraft","CreateLinkSource");
  1552.  
  1553.     SOM_TRY
  1554.  
  1555.     ODStorageUnitID    id;
  1556.     ODLinkSource*    linkSource = kODNULL;
  1557.  
  1558.     somSelf->FailIfNotExclusiveWrite(ev);
  1559.  
  1560.     TempODStorageUnit su = somSelf->CreateSU(ev, kODNULL, kODLinkSource);
  1561.  
  1562.     // The implementation of CMLinkSourceIterator depends on this property being present
  1563.     // in link source storage units and nowhere else.
  1564.     
  1565.     SetStorageUnitType(ev, _fPermissions, su, kODLinkSource);
  1566.     
  1567.     linkSource = new ODLinkSource();
  1568.     THROW_IF_NULL(linkSource,kODErrCannotCreateLink);
  1569.     
  1570.     TempODLink link = kODNULL;
  1571.     TRY
  1572.         link = somSelf->CreateLink(ev);
  1573.     CATCH_ALL
  1574.         linkSource->ReleaseAll(ev);
  1575.         delete linkSource;
  1576.         RERAISE;
  1577.     ENDTRY
  1578.         
  1579.     id = su->GetID(ev);
  1580.     
  1581.     _fPersistentObjects->ReplaceEntry(&id, &linkSource);
  1582.     
  1583.     linkSource->InitLinkSource(ev, su.DontRelease(), part);
  1584.     // ("DontDelete" prevents su from being auto-released by destructor)
  1585.     
  1586.     link->SetLinkSource(ev, linkSource);
  1587.     linkSource->SetLink(ev, link);
  1588.  
  1589.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1590.  
  1591.     return linkSource;
  1592.  
  1593.     SOM_CATCH_ALL
  1594.     SOM_ENDTRY
  1595.     return kODNULL;
  1596. }
  1597.  
  1598. //------------------------------------------------------------------------------
  1599. // CMDraft: AcquireLinkSource
  1600. //------------------------------------------------------------------------------
  1601.  
  1602. SOM_Scope ODLinkSource*  SOMLINK CMDraftAcquireLinkSource(CMDraft *somSelf, Environment *ev,
  1603.         ODStorageUnitID id)
  1604. {
  1605.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1606.     CMDraftMethodDebug("CMDraft","AcquireLinkSource");
  1607.  
  1608.     SOM_TRY
  1609.  
  1610.     if (id == kODNULLID)
  1611.         THROW(kODErrIllegalNullIDInput);
  1612.         
  1613.     ODLinkSource* linkSource = (ODLinkSource*) kODNULL;
  1614.     
  1615.     linkSource = ((ODLinkSource*) somSelf->RetrievePersistentObject(ev, id));
  1616.  
  1617.     if (linkSource == (ODLinkSource*) kODNULL) {    
  1618.         linkSource = new ODLinkSource();
  1619.         if (linkSource == (ODLinkSource*) kODNULL)
  1620.                 THROW(kODErrCannotAcquireLink);
  1621.             
  1622.         ODStorageUnit*    su = (ODStorageUnit*) kODNULL;
  1623.         ODVolatile(su);
  1624.         ODVolatile(id);
  1625.         TRY
  1626.             su = somSelf->AcquireStorageUnit(ev, id);
  1627.             _fPersistentObjects->ReplaceEntry(&id, &linkSource);
  1628.             linkSource->InitLinkSourceFromStorage(ev, su);
  1629.              SetStorageUnitType(ev, _fPermissions, su, kODLinkSource);
  1630.         CATCH_ALL
  1631.             if (su != (ODStorageUnit*) kODNULL) {
  1632.                 _fPersistentObjects->RemoveEntry(&id);
  1633.                 su->Release(ev);
  1634.                 }
  1635.             linkSource->ReleaseAll(ev);
  1636.             delete linkSource;
  1637.             RERAISE;
  1638.         ENDTRY
  1639.         }
  1640.  
  1641.     return linkSource;
  1642.  
  1643.     SOM_CATCH_ALL
  1644.     SOM_ENDTRY
  1645.     return kODNULL;
  1646. }
  1647.  
  1648. //------------------------------------------------------------------------------
  1649. // CMDraft: RemoveLinkSource
  1650. //------------------------------------------------------------------------------
  1651.  
  1652. SOM_Scope void  SOMLINK CMDraftRemoveLinkSource(CMDraft *somSelf, Environment *ev,
  1653.         ODLinkSource* linkSource)
  1654. {
  1655.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1656.     CMDraftMethodDebug("CMDraft","RemoveLinkSource");
  1657.  
  1658.     SOM_TRY
  1659.  
  1660.     somSelf->FailIfNotExclusiveWrite(ev);
  1661.         
  1662.     somSelf->RemovePersistentObject(ev, linkSource);
  1663.  
  1664.     SOM_CATCH_ALL
  1665.     SOM_ENDTRY
  1666. }
  1667.  
  1668. //------------------------------------------------------------------------------
  1669. // CMDraft: CreateLink
  1670. //------------------------------------------------------------------------------
  1671.  
  1672. SOM_Scope ODLink*  SOMLINK CMDraftCreateLink(CMDraft *somSelf, Environment *ev)
  1673. {
  1674.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1675.     CMDraftMethodDebug("CMDraft","CreateLink");
  1676.  
  1677.     SOM_TRY
  1678.  
  1679.     ODStorageUnitID    id;
  1680.     ODLink*            link = kODNULL;
  1681.     ODStorageUnit*     su;
  1682.  
  1683.     su = somSelf->CreateSU(ev, kODNULL, kODLink);
  1684.     
  1685.     // The implementation of CMLinkIterator depends on this property being present
  1686.     // in link storage units and nowhere else.
  1687.     SetStorageUnitType(ev, _fPermissions, su, kODLink);
  1688.     
  1689.     link = new ODLink();
  1690.     if (link == kODNULL) 
  1691.     {
  1692.         delete su;
  1693.         THROW(kODErrCannotCreateLink);
  1694.     }
  1695.  
  1696.     id = su->GetID(ev);
  1697.     _fPersistentObjects->ReplaceEntry(&id, &link);
  1698.     
  1699.     link->InitLink(ev, su);
  1700.  
  1701.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1702.  
  1703.     return link;
  1704.  
  1705.     SOM_CATCH_ALL
  1706.     SOM_ENDTRY
  1707.     return kODNULL;
  1708. }
  1709.  
  1710. //------------------------------------------------------------------------------
  1711. // CMDraft: AcquireLink
  1712. //------------------------------------------------------------------------------
  1713.  
  1714. SOM_Scope ODLink*  SOMLINK CMDraftAcquireLink(CMDraft *somSelf, Environment *ev,
  1715.         ODStorageUnitID id,ODLinkSpec* linkSpec)
  1716. {
  1717.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1718.     CMDraftMethodDebug("CMDraft","AcquireLink");
  1719.  
  1720.     SOM_TRY
  1721.     
  1722.     ODLink* link = (ODLink*) kODNULL;
  1723.  
  1724.     if (id != (ODStorageUnitID) kODNULL) {
  1725.         link = ((ODLink*) somSelf->RetrievePersistentObject(ev, id));
  1726.         if (link == (ODLink*) kODNULL) {    
  1727.             link = new ODLink();
  1728.             if (link == kODNULL)
  1729.                 THROW(kODErrCannotAcquireLink);
  1730.             
  1731.             ODStorageUnit*    su = (ODStorageUnit*) kODNULL;
  1732.             ODVolatile(su);
  1733.             ODVolatile(id);
  1734.             TRY
  1735.                 su = somSelf->AcquireStorageUnit(ev, id);
  1736.                 _fPersistentObjects->ReplaceEntry(&id, &link);
  1737.                 link->InitLinkFromStorage(ev, su);
  1738.                  SetStorageUnitType(ev, _fPermissions, su, kODLink);
  1739.             CATCH_ALL
  1740.                 if (su != (ODStorageUnit*) kODNULL) {
  1741.                     _fPersistentObjects->RemoveEntry(&id);
  1742.                     su->Release(ev);
  1743.                     }
  1744.                 link->ReleaseAll(ev);
  1745.                 delete link;
  1746.                 RERAISE;
  1747.             ENDTRY
  1748.             }
  1749.         }
  1750.     else if (linkSpec == (ODLinkSpec*) kODNULL) {
  1751.         THROW(kODErrInsufficientInfoInParams);
  1752.         }
  1753.     else if (linkSpec->FromThisDraft(ev)) {
  1754.         ODPart* part = linkSpec->GetPart(ev);
  1755.         ODByteArray partData = linkSpec->GetPartData(ev);
  1756.         ODVolatile(partData);
  1757.         ODLinkSource* linkSource = kODNULL;
  1758.         ODVolatile(linkSource);
  1759.         TRY
  1760.             linkSource = part->CreateLink(ev, &partData);
  1761.             if ( linkSource != (ODLinkSource*) kODNULL ) {
  1762.                 link = linkSource->GetLink(ev);
  1763.                 if ( link != (ODLink*) kODNULL )
  1764.                     link->Acquire(ev);
  1765.                 }
  1766.         CATCH_ALL
  1767.             DisposeByteArrayStruct(partData);
  1768.             ODReleaseObject(ev, linkSource);
  1769.             RERAISE;
  1770.         ENDTRY
  1771.         DisposeByteArrayStruct(partData);
  1772.         ODReleaseObject(ev, linkSource);
  1773.         }
  1774.     else {
  1775.         // This link spec originated in another document; forward the
  1776.         // AcquireLink call to the originating draft.
  1777.         ODSession* session = _fDocument->GetContainer(ev)->GetStorageSystem(ev)->GetSession(ev);
  1778.         if (session != kODNULL) {
  1779.             ODLinkSource* linkSource = kODNULL;
  1780.             ODVolatile(linkSource);
  1781.             TRY
  1782.                 linkSource = session->GetLinkManager(ev)->CreateLink(ev, somSelf, linkSpec);
  1783.                 if ( linkSource != (ODLinkSource*) kODNULL ) {
  1784.                     link = linkSource->GetLink(ev);
  1785.                     if ( link != (ODLink*) kODNULL )
  1786.                         link->Acquire(ev);
  1787.                     }
  1788.             CATCH_ALL
  1789.                 ODReleaseObject(ev, linkSource);
  1790.                 RERAISE;
  1791.             ENDTRY
  1792.             ODReleaseObject(ev, linkSource);
  1793.             }
  1794.         }
  1795.     return link;
  1796.  
  1797.     SOM_CATCH_ALL
  1798.     SOM_ENDTRY
  1799.     return kODNULL;
  1800. }
  1801.  
  1802. //------------------------------------------------------------------------------
  1803. // CMDraft: ReleaseLink
  1804. //------------------------------------------------------------------------------
  1805.  
  1806. SOM_Scope void  SOMLINK CMDraftReleaseLink(CMDraft *somSelf, Environment *ev,
  1807.         ODLink* link)
  1808. {
  1809.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1810.     CMDraftMethodDebug("CMDraft","ReleaseLink");
  1811.  
  1812.     SOM_TRY
  1813.  
  1814.     somSelf->ReleasePersistentObject(ev, link);
  1815.  
  1816.     SOM_CATCH_ALL
  1817.     SOM_ENDTRY
  1818. }
  1819.  
  1820. //------------------------------------------------------------------------------
  1821. // CMDraft: ReleaseLinkSource
  1822. //------------------------------------------------------------------------------
  1823.  
  1824. SOM_Scope void  SOMLINK CMDraftReleaseLinkSource(CMDraft *somSelf, Environment *ev,
  1825.         ODLinkSource* linkSource)
  1826. {
  1827.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1828.     CMDraftMethodDebug("CMDraft","ReleaseLinkSource");
  1829.  
  1830.     SOM_TRY
  1831.  
  1832.     somSelf->ReleasePersistentObject(ev, linkSource);
  1833.  
  1834.     SOM_CATCH_ALL
  1835.     SOM_ENDTRY
  1836. }
  1837.  
  1838. //------------------------------------------------------------------------------
  1839. // CMDraft: RemoveLink
  1840. //------------------------------------------------------------------------------
  1841.  
  1842. SOM_Scope void  SOMLINK CMDraftRemoveLink(CMDraft *somSelf, Environment *ev,
  1843.         ODLink* link)
  1844. {
  1845.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1846.     CMDraftMethodDebug("CMDraft","RemoveLink");
  1847.  
  1848.     SOM_TRY
  1849.  
  1850.     somSelf->FailIfNotExclusiveWrite(ev);
  1851.         
  1852.     somSelf->RemovePersistentObject(ev, link);
  1853.  
  1854.     SOM_CATCH_ALL
  1855.     SOM_ENDTRY
  1856. }
  1857.  
  1858. //------------------------------------------------------------------------------
  1859. // CMDraft: GetPersistentObjectID
  1860. //------------------------------------------------------------------------------
  1861.  
  1862. SOM_Scope ODPersistentObjectID  SOMLINK CMDraftGetPersistentObjectID(CMDraft *somSelf, Environment *ev,
  1863.         ODPersistentObject* object,
  1864.         ODObjectType    objectType)
  1865. {
  1866.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1867.     CMDraftMethodDebug("CMDraft","GetPersistentObjectID");
  1868.  
  1869.     // kODNULLID isn't reserved as a null container manager object id.
  1870.     // If this method returns a SOM error, clients must ignore the return value. [cc]
  1871.     ODPersistentObjectID persistentID = kODNULLID; ODVolatile(persistentID);
  1872.     
  1873.     SOM_TRY
  1874.  
  1875.     ASSERT(ODISOStrEqual(objectType, kODPartObject) || ODISOStrEqual(objectType, kODFrameObject),
  1876.             kODErrInvalidObjectType);
  1877.  
  1878.     CMObjectID cmID = somSelf->GetCMObjectID(ev, object);
  1879.     somSelf->InitScriptingIDManager(ev);
  1880.     persistentID = _fScriptingIDMgr->GetScriptingID(ev, cmID);
  1881.  
  1882.     SOM_CATCH_ALL
  1883.     SOM_ENDTRY
  1884.  
  1885.     return persistentID;
  1886. }
  1887.  
  1888. //------------------------------------------------------------------------------
  1889. // CMDraft: AcquirePersistentObject
  1890. //------------------------------------------------------------------------------
  1891.  
  1892. SOM_Scope ODPersistentObject* SOMLINK CMDraftAcquirePersistentObject(CMDraft *somSelf, Environment *ev,
  1893.         ODPersistentObjectID objectID,
  1894.         ODObjectType*    objectType)
  1895. {
  1896.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1897.     CMDraftMethodDebug("CMDraft","AcquirePersistentObject");
  1898.     
  1899.     SOM_TRY
  1900.     
  1901.         somSelf->InitScriptingIDManager(ev);
  1902.         return _fScriptingIDMgr->AcquirePersistentObject(ev, objectID, objectType);
  1903.  
  1904.     SOM_CATCH_ALL
  1905.     SOM_ENDTRY
  1906.     return kODNULL;
  1907. }
  1908.  
  1909. //------------------------------------------------------------------------------
  1910. // CMDraft: AcquirePersistentObjectByCMObjectID
  1911. //------------------------------------------------------------------------------
  1912.  
  1913. SOM_Scope ODPersistentObject* SOMLINK CMDraftAcquirePersistentObjectByCMObjectID(CMDraft *somSelf, Environment *ev,
  1914.         CMObjectID objectID,
  1915.         ODObjectType* objectType)
  1916. {
  1917.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1918.     CMDraftMethodDebug("CMDraft","AcquirePersistentObjectByCMObjectID");
  1919.     
  1920.     SOM_TRY
  1921.     
  1922.     *objectType = kODNULL;
  1923.     ODPersistentObject*    object = kODNULL;
  1924.     ODStorageUnitID    id = kODNULLID;
  1925.     
  1926.     if (objectID == 0)
  1927.         THROW(kODErrIllegalNullIDInput);
  1928.  
  1929.     CMContainer cmContainer = somSelf->GetCMContainer(ev);
  1930.     ODSessionMustHaveCMAllocReserve(cmContainer);
  1931.     
  1932.     CMObject cmObject = CMGetObject(cmContainer, objectID);
  1933.     if (cmObject == kODNULL)
  1934.         THROW(kODErrInvalidPersistentObjectID);
  1935.         
  1936.     if (_fIDList->ObjectExists(cmObject) != kODFalse) {
  1937.         id = _fIDList->GetID(cmObject);
  1938.         CMReleaseObject(cmObject);
  1939.     }
  1940.     else
  1941.         id = _fIDList->Add(cmObject);
  1942.  
  1943.     ODSessionRestoreCMAllocReserve(cmContainer);
  1944.     
  1945.     TempODStorageUnit su = somSelf->AcquireStorageUnit(ev, id);
  1946.     if (su == kODNULL)
  1947.         THROW(kODErrInvalidPersistentObjectID);
  1948.  
  1949.     TempODPtr buffer;
  1950.     if ((buffer = ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL)) != kODNULL)
  1951.     {
  1952.         if (ODISOStrEqual((ODISOStr) (ODPtr) buffer, kODPartObject) != kODFalse)
  1953.             object = somSelf->AcquirePart(ev, id);
  1954.         else if (ODISOStrEqual((ODISOStr) (ODPtr) buffer, kODFrameObject) != kODFalse)
  1955.             object = somSelf->AcquireFrame(ev, id);
  1956.         else
  1957.             THROW(kODErrInvalidPersistentObjectID);
  1958.         
  1959.         if (object != kODNULL)
  1960.         {
  1961.             *objectType = (ODType) (ODPtr) buffer;
  1962.             buffer = kODNULL;    // don't delete [cc]
  1963.         }
  1964.     }
  1965.  
  1966.     return object;
  1967.  
  1968.     SOM_CATCH_ALL
  1969.     SOM_ENDTRY
  1970.     return kODNULL;
  1971. }
  1972.  
  1973. //------------------------------------------------------------------------------
  1974. // CMDraft: GetCMObjectID
  1975. //------------------------------------------------------------------------------
  1976. // This is identical to the old GetPersistentObjectID method, minus the
  1977. // objectType parameter.
  1978.  
  1979. SOM_Scope CMObjectID SOMLINK CMDraftGetCMObjectID(CMDraft *somSelf, Environment *ev,
  1980.         ODPersistentObject* object)
  1981. {
  1982.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1983.     CMDraftMethodDebug("CMDraft","GetCMObjectID");
  1984.  
  1985.     SOM_TRY
  1986.  
  1987.     CMStorageUnit* su = (CMStorageUnit*) object->GetStorageUnit(ev);
  1988.     
  1989.     if (su == kODNULL)
  1990.         THROW(kODErrInvalidPersistentObject);
  1991.  
  1992.     return su->GetObjectID(ev);
  1993.  
  1994.     SOM_CATCH_ALL
  1995.     SOM_ENDTRY
  1996.     return kODNULLID;
  1997. }
  1998.  
  1999. //------------------------------------------------------------------------------
  2000. // CMDraft: TransferPersistentObjectID
  2001. //------------------------------------------------------------------------------
  2002.  
  2003. SOM_Scope ODPersistentObjectID  SOMLINK CMDraftTransferPersistentObjectID(CMDraft *somSelf, Environment *ev,
  2004.         ODPersistentObject* fromObject,
  2005.         ODPersistentObject* toObject)
  2006. {
  2007.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2008.     CMDraftMethodDebug("CMDraft","TransferPersistentObjectID");
  2009.  
  2010.     ODPersistentObjectID objectID;
  2011.  
  2012.     SOM_TRY
  2013.  
  2014.         CMObjectID fromCMID = somSelf->GetCMObjectID(ev, fromObject);
  2015.         CMObjectID toCMID = somSelf->GetCMObjectID(ev, toObject);
  2016.         somSelf->InitScriptingIDManager(ev);
  2017.         objectID = _fScriptingIDMgr->TransferScriptingID(ev, fromCMID, toCMID);
  2018.  
  2019.     SOM_CATCH_ALL_ENDTRY
  2020.  
  2021.     return objectID;
  2022. }
  2023.  
  2024. //------------------------------------------------------------------------------
  2025. // CMDraft: ReleaseStorageUnit
  2026. //------------------------------------------------------------------------------
  2027.  
  2028. SOM_Scope ODDraft*  SOMLINK CMDraftReleaseStorageUnit(CMDraft *somSelf, Environment *ev,
  2029.         ODStorageUnitID id)
  2030. {
  2031.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2032.     CMDraftMethodDebug("CMDraft","ReleaseStorageUnit");
  2033.  
  2034.     SOM_TRY
  2035.  
  2036.     ODStorageUnit*    su = kODNULL;
  2037.     
  2038.     if (! _fStorageUnits->GetValue(&id, &su))
  2039.         THROW(kODErrInvalidStorageUnit);
  2040.     
  2041.     if (su->GetRefCount(ev) != 0)
  2042.         THROW(kODErrRefCountGreaterThanZero);
  2043.         
  2044.     if (_fDraftProperties != kODNULL) {
  2045.         if (id == _fDraftProperties->GetID(ev))
  2046.             _fDraftProperties = kODNULL;
  2047.     }
  2048.     
  2049.     return somSelf;
  2050.  
  2051.     SOM_CATCH_ALL
  2052.     SOM_ENDTRY
  2053.     return somSelf;
  2054. }
  2055.  
  2056. //------------------------------------------------------------------------------
  2057. // CMDraft: ~CMDraft
  2058. //------------------------------------------------------------------------------
  2059.  
  2060. SOM_Scope void  SOMLINK CMDraftsomUninit(CMDraft *somSelf)
  2061. {
  2062.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2063.     CMDraftMethodDebug("CMDraft","somUninit");
  2064.  
  2065.     TRY{
  2066.         Environment*    ev = somGetGlobalEnvironment();
  2067.     
  2068. #if ODDebug_DebugRefCount
  2069.         if (somSelf->GetRefCount(ev) != 0)
  2070.             DebugStr("\pRefCount of Draft is not 0 at uninit.");
  2071.         somPrintf("~CMDraft %x RefCount %d EmbeddedCtr %x CMCtr %x\n", 
  2072.                     somSelf,
  2073.                     somSelf->GetRefCount(ev),
  2074.                     somSelf->GetEmbeddedContainer(ev),
  2075.                     somSelf->GetCMContainer(ev));
  2076. #endif
  2077.  
  2078.         delete _fScriptingIDMgr;
  2079.         somSelf->DeleteCollections(ev);
  2080.     }CATCH_ALL{
  2081.            // Ignore exception
  2082.     }ENDTRY
  2083. }
  2084.  
  2085. //------------------------------------------------------------------------------
  2086. // CMDraft: InitDraft
  2087. //------------------------------------------------------------------------------
  2088.  
  2089. SOM_Scope void  SOMLINK CMDraftInitDraft(CMDraft *somSelf, Environment *ev,
  2090.         ODDocument* document, ODDraftID id, ODDraftPermissions perms)
  2091. {
  2092.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2093.     CMDraftMethodDebug("CMDraft","InitDraft");
  2094.  
  2095.     SOM_TRY
  2096.     
  2097.     /* Moved from somInit. SOM itself sets fields to zero
  2098.     _fChangedFromPrev = kODFalse;
  2099.     
  2100.     _fDocument = kODNULL;
  2101.     _fID = 0;
  2102.     _fPermissions = kODDPNone;
  2103.     _fEmbeddedContainer = kODNULL;
  2104.     _fVersionID = kODTombstonedVersion;
  2105.     _fIsNewDraft = kODFalse;
  2106.     
  2107.     _fExternalized = kODFalse;
  2108.     _fRemoveChangeOnAbort = kODFalse;
  2109.     
  2110.     _fStorageUnits = kODNULL;
  2111.     _fPersistentObjects = kODNULL;
  2112.     
  2113.     _fIDList = kODNULL;
  2114.     _fDraftProperties = kODNULL;
  2115.     
  2116.     _fDestDraft = kODNULL;
  2117.     _fDestFrame = kODNULL;
  2118.     _fClonedSUIDs = kODNULL;
  2119.     _fWeakClonedSUIDs = kODNULL;
  2120.     _fSavedWeakClonedSUIDs = kODNULL;
  2121.     _fLinksToCloneSUIDs = kODNULL;
  2122.     _fCurrentKey = kODNULL;
  2123.     _fLockCount = 0;
  2124.  
  2125.     _fAnyFrameCloned = kODFalse;
  2126.     _fRootPartReused = kODFalse;
  2127.  
  2128.     _fOrigTopVersionDraftID = 0;
  2129.  
  2130.     _fHeap = kDefaultHeapID;
  2131.     _fScriptingIDMgr = kODNULL;
  2132.     */
  2133.     _fVersionID = kODTombstonedVersion; 
  2134.     
  2135.     somSelf->InitRefCntObject(ev); 
  2136.  
  2137. #ifdef ODDebug_VersionList
  2138.     ((CMDocument*) document)->GetVersionList(ev)->Print(">>>Entering InitDraft");
  2139. #endif
  2140.     
  2141.     _fDocument = (CMDocument*) document;
  2142.     _fID = id;
  2143.     _fPermissions = perms;
  2144.  
  2145.     VersionList*    versionList = kODNULL;
  2146.  
  2147.     if (_fDocument == kODNULL)
  2148.         THROW(kODErrIllegalNullDocumentInput);
  2149.         
  2150.     if (_fID == kODNULL) {
  2151.         versionList = _fDocument->GetVersionList(ev);
  2152.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2153.             
  2154.         _fID = versionList->CreateDraft();
  2155.         _fIsNewDraft = kODTrue;
  2156.         _fRemoveChangeOnAbort = kODTrue;
  2157.         
  2158. #if !TestFlushContainer
  2159.         _fDocument->ExternalizeVersionList(ev, kODFalse);
  2160. #endif
  2161.     }
  2162.     
  2163.     somSelf->CreateCollections(ev);
  2164.             
  2165. #if lazyOpen
  2166.     _fExternalized = kODFalse;
  2167. #else
  2168.     if (_fPermissions == kODDPReadOnly)
  2169.         somSelf->OpenVersion(ev);
  2170.     else
  2171.         somSelf->CreateVersion(ev);
  2172. #endif
  2173.         
  2174.     _fHeap = _fDocument->GetHeap(ev);
  2175.  
  2176. #ifdef ODDebug_Unloading_Classes
  2177.     SetOutputMode(kWriteToFile);
  2178. #endif
  2179.  
  2180. #ifdef ODDebug_VersionList
  2181.     _fDocument->GetVersionList(ev)->Print(">>>Exiting InitDraft");
  2182. #endif
  2183.  
  2184.     SOM_CATCH_ALL
  2185.     SOM_ENDTRY
  2186. }
  2187.  
  2188. //------------------------------------------------------------------------------
  2189. // CMDraft: Purge
  2190. //------------------------------------------------------------------------------
  2191.  
  2192. SOM_Scope ODSize  SOMLINK CMDraftPurge(CMDraft *somSelf, Environment *ev,
  2193.         ODSize size)
  2194. {
  2195.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2196.     CMDraftMethodDebug("CMDraft","Purge");
  2197.  
  2198.     ODULong    runningTotal = 0; ODVolatile( runningTotal );
  2199.         
  2200.     SOM_TRY
  2201.  
  2202.         OpenHashTableIterator    i(_fPersistentObjects);
  2203.         ODStorageUnitID        id;
  2204.         ODPersistentObject*    object;
  2205.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  2206.             TRY
  2207.                 runningTotal += object->Purge(ev, size);
  2208.             CATCH_ALL
  2209.             ENDTRY
  2210.  
  2211.             TRY
  2212.                 if (object->GetRefCount(ev) == 0) {
  2213.                     object->ReleaseAll(ev);
  2214.                 }
  2215.             CATCH_ALL
  2216.             ENDTRY
  2217.         }
  2218.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  2219.             if (object->GetRefCount(ev) == 0) {
  2220.                 i.RemoveCurrent();
  2221.                 delete object;
  2222.             }
  2223.         }
  2224.         // ShrinkToFit() allocates new tables first, and this aggravates
  2225.         // low memory conditions during Purge().
  2226.         // _fPersistentObjects->ShrinkToFit(/*extraSlots*/ 0);
  2227.                 
  2228.         // purge all storage units, but don't release CMObjects 
  2229.  
  2230.         runningTotal += PurgeAllStorageUnits(ev, _fStorageUnits, kODNULL);
  2231.  
  2232.         // dh - call parent Purge method
  2233.         runningTotal += parent_Purge(somSelf, ev, size);
  2234.         
  2235.     SOM_CATCH_ALL
  2236.         WARN("Error %ld trying to purge in CMDraftPurge",ErrorCode());
  2237.         SetErrorCode(kODNoError);        // dh - Eat the exception; Purge should not 
  2238.                                         // propagate it because clients function
  2239.                                         // fine whether memory was purged or not.
  2240.     SOM_ENDTRY
  2241.  
  2242.     return runningTotal;
  2243. }
  2244.  
  2245. //------------------------------------------------------------------------------
  2246. // CMDraft: CreateSU
  2247. //------------------------------------------------------------------------------
  2248.  
  2249. SOM_Scope ODStorageUnit*  SOMLINK CMDraftCreateSU(CMDraft *somSelf, Environment *ev,
  2250.         ODStorageUnitID id, ODType suType)
  2251. {
  2252.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2253.     CMDraftMethodDebug("CMDraft","CreateSU");
  2254.     
  2255.     ODStorageUnit*    su = kODNULL;
  2256.  
  2257.     SOM_TRY
  2258.  
  2259.     CMObject        object = kODNULL;
  2260.     CMContainer        cmContainer = somSelf->GetCMContainer(ev);
  2261.     ODSessionMustHaveCMAllocReserve(cmContainer);
  2262.  
  2263.     ODVolatile(su);
  2264.     ODVolatile(object);
  2265.     TRY    
  2266.         
  2267.         // Create CMObject if necessary
  2268.         
  2269.         if (id == kODNULL) {
  2270.             if ((object = CMNewObject(cmContainer)) == kODNULL)
  2271.                 THROW(kODErrBentoCannotNewObject);
  2272.                 
  2273.             id = _fIDList->Add(object);
  2274.         }        
  2275.  
  2276.         // Create the Storage Unit
  2277.         su = NewCMStorageUnit(somSelf->GetHeap(ev));
  2278.         su->InitStorageUnit(ev, somSelf, id);
  2279.         
  2280.     CATCH_ALL
  2281.         
  2282.         if (object != kODNULL)
  2283.             CMReleaseObject(object);
  2284.             
  2285.         if (su != kODNULL)
  2286.             delete su;
  2287.             
  2288.         if (ErrorCode() == kODErrBentoInvalidObject)
  2289.             THROW(kODErrInvalidID);
  2290.         else
  2291.             RERAISE;
  2292.             
  2293.     ENDTRY
  2294.     ODSessionRestoreCMAllocReserve(cmContainer);
  2295.  
  2296.     // Add Storage Unit to outstanding SU collection
  2297.     
  2298.     _fStorageUnits->ReplaceEntry(&id, &su);
  2299.     
  2300.     SOM_CATCH_ALL
  2301.         su = kODNULL;
  2302.     SOM_ENDTRY
  2303.  
  2304.     return su;
  2305. }
  2306.  
  2307. //------------------------------------------------------------------------------
  2308. // CMDraft: SetChangedFromPrevFlag
  2309. //------------------------------------------------------------------------------
  2310.  
  2311. SOM_Scope void  SOMLINK CMDraftSetChangedFromPrevFlag(CMDraft *somSelf, Environment *ev,
  2312.         ODBoolean changed)
  2313. {
  2314.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2315.     CMDraftMethodDebug("CMDraft","SetChangedFromPrevFlag");
  2316.  
  2317.     if (changed != kODFalse) {
  2318.         SOM_TRY
  2319.             somSelf->FailIfNotExclusiveWrite(ev);
  2320.         SOM_CATCH_ALL
  2321.         SOM_ENDTRY
  2322.     }
  2323.     _fChangedFromPrev = changed;
  2324. }
  2325.  
  2326. static void SetupForUpdatingDraft(Environment* ev,
  2327.                                         CMDocument* localDoc,
  2328.                                         ODVersionID prevVersionID,
  2329.                                         CMValue version)
  2330. {
  2331.     ODBentoContainer*    localContainer = (ODBentoContainer*) localDoc->GetContainer(ev);
  2332.     ODBentoContainer*    container = kODNULL;
  2333.     
  2334.     // check to see whether we need to do a update
  2335.     container = localContainer->GetTargetContainer(ev);
  2336.     
  2337.     if (container != kODNULL) {
  2338.         
  2339.         // get the target document
  2340.         CMDocument*        targetDoc = localContainer->GetTargetDocument(ev);
  2341.         
  2342.         // find its version list
  2343.         VersionList*    versionList = targetDoc->GetVersionList(ev);
  2344.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2345.     
  2346.         // get the latest draft
  2347.         ODDraftID    latestDraftID = versionList->GetLatestDraftID();
  2348.         
  2349.         // get the version id of the latest draft
  2350.         prevVersionID = versionList->GetDraft(latestDraftID);
  2351.     }
  2352.     else {
  2353.         container = localContainer;
  2354.     }
  2355.     // Note: getting/setting refcon's does not allocate memory in Bento:
  2356.     
  2357.     // get the name for indirection
  2358.     ODType prevVersionName = GetVersionNameFromVersionID(prevVersionID, localDoc->GetHeap(ev));
  2359.     
  2360.     // store name so that it can be passed to handler
  2361.     CMSetValueRefCon(version, prevVersionName);
  2362.  
  2363.     // get cmContainer so that we can assess CMSession
  2364.     CMContainer cmContainer = container->GetCMContainer(ev);
  2365.  
  2366.     // Save the outermost container for embedded container creation.
  2367.     ODSessionRefCon* sessionRefCon = (ODSessionRefCon*) CMGetSessionRefCon(cmContainer);
  2368.     sessionRefCon->container = container;
  2369. }
  2370.  
  2371. //------------------------------------------------------------------------------
  2372. // CMDraft: CreateVersion
  2373. //------------------------------------------------------------------------------
  2374.  
  2375. SOM_Scope void  SOMLINK CMDraftCreateVersion(CMDraft *somSelf, Environment *ev)
  2376. {
  2377.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2378.     CMDraftMethodDebug("CMDraft","CreateVersion");
  2379.     
  2380.     SOM_TRY
  2381.  
  2382.     CMContainer                cmContainer = ((ODBentoContainer*) _fDocument->GetContainer(ev))->GetCMContainer(ev);
  2383.     CMObject                versionObject = kODNULL;
  2384.     CMType                    versionNameType = kODNULL;
  2385.     ODType                    versionName = kODNULL;
  2386.     CMProperty                versionNameProperty = kODNULL;
  2387.     CMValue                    versionNameValue = kODNULL;
  2388.     CMType                    versionDataType = kODNULL;
  2389.     CMProperty                versionDataProperty = kODNULL;
  2390.     CMValue                    version = kODNULL;
  2391.     
  2392.     VersionList*            versionList = kODNULL;
  2393.  
  2394.     versionList = _fDocument->GetVersionList(ev);
  2395.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2396.  
  2397.     _fOrigTopVersionDraftID = versionList->GetSameVersionDraftID(_fID);
  2398.     _fPrevVersionID = versionList->GetCurrentVersion(_fID);
  2399.     _fVersionID = versionList->CreateVersion(_fID);
  2400.     
  2401.     ODSessionMustHaveCMAllocReserve(cmContainer);
  2402.  
  2403.     versionObject = CMNewObject(cmContainer);
  2404.     versionNameType = CMRegisterType(cmContainer, kODISOStr);
  2405.  
  2406.     versionName = GetVersionNameFromVersionID(_fVersionID, somSelf->GetHeap(ev));
  2407.     versionNameProperty = CMRegisterProperty(cmContainer, versionName);
  2408.     
  2409.     versionNameValue = CMNewValue(versionObject, versionNameProperty, versionNameType);
  2410.     CMWriteValueData(versionNameValue, "", 0, 1);
  2411.     
  2412.     versionDataType = CMRegisterType(cmContainer, kODEmbeddedContainerType);
  2413.     versionDataProperty = CMRegisterProperty(cmContainer, kODEmbeddedContainerProperty);
  2414.     version = CMNewValue(versionObject, versionDataProperty, versionDataType);
  2415.     if (version == kODNULL)
  2416.         THROW(kODErrCannotCreateDraftVersion);
  2417.     CMWriteValueData(version, "", 0, 0);                /* Make the container manager happy */
  2418.  
  2419.     ODSessionRestoreCMAllocReserve(cmContainer);
  2420.     
  2421.     SetupForUpdatingDraft(ev, _fDocument, _fPrevVersionID, version);
  2422.     
  2423. #ifdef ODDebug_CMDraft
  2424.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2425.     somPrintf("CreateVersion: CMDocument %x DraftID %d IsNewDraft %d versionID %d prevVersionID %d\n", tempDoc, somSelf->GetID(ev), somSelf->IsNewDraft(ev), _fVersionID, _fPrevVersionID);    
  2426. #endif
  2427.  
  2428.     ODEmbeddedContainerID    containerID;
  2429.     containerID.cmValue = version;
  2430.     containerID.shouldMerge = (somSelf->IsNewDraft(ev) ? kODFalse : kODTrue);
  2431.     ODByteArray*    ba = CreateByteArray(&containerID, sizeof(ODEmbeddedContainerID));
  2432.     _fEmbeddedContainer = (ODEmbeddedContainer*) 
  2433.             _fDocument->GetContainer(ev)->GetStorageSystem(ev)->CreateContainer(ev, kODBentoEmbeddedContainer, ba);
  2434.     DisposeByteArray(ba);
  2435.     
  2436.     if (versionName != kODNULL)
  2437.         ODDisposePtr(versionName);
  2438.  
  2439.     _fExternalized = kODFalse;
  2440.  
  2441.     somSelf->OpenCollections(ev);
  2442.     
  2443.     SOM_CATCH_ALL
  2444.     SOM_ENDTRY
  2445. }
  2446.  
  2447. //------------------------------------------------------------------------------
  2448. // CMDraft: OpenVersion
  2449. //------------------------------------------------------------------------------
  2450.  
  2451. SOM_Scope void  SOMLINK CMDraftOpenVersion(CMDraft *somSelf, Environment *ev)
  2452. {
  2453.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2454.     CMDraftMethodDebug("CMDraft","OpenVersion");
  2455.     
  2456.     SOM_TRY
  2457.  
  2458.     CMContainer                cmContainer = ((ODBentoContainer*) _fDocument->GetContainer(ev))->GetCMContainer(ev);
  2459.     ODType                    versionName = kODNULL;
  2460.     ODType                    oldVersionName = kODNULL;
  2461.     CMType                    versionDataType;
  2462.     CMProperty                versionDataProperty;
  2463.     CMProperty                versionNameProperty;
  2464.     CMObject                versionObject;
  2465.     CMValue                    version;
  2466.  
  2467.     VersionList*            versionList;
  2468.     
  2469.     versionList = _fDocument->GetVersionList(ev);
  2470.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2471.         
  2472.     _fVersionID = versionList->GetCurrentVersion(_fID);
  2473.     _fPrevVersionID = _fVersionID;
  2474.     if (_fVersionID == kODTombstonedVersion)
  2475.         THROW(kODErrDraftHasBeenDeleted);
  2476.     
  2477.     if (_fPermissions == kODDPReadOnly) {
  2478.         ODSessionMustHaveCMAllocReserve(cmContainer);
  2479.     
  2480.         MyDebugStr("**** OpenVersion: kODDPReadOnly.\n");
  2481.         versionDataType = CMRegisterType(cmContainer, kODEmbeddedContainerType);
  2482.         versionDataProperty = CMRegisterProperty(cmContainer, kODEmbeddedContainerProperty);
  2483.         
  2484.         versionName = GetVersionNameFromVersionID(_fVersionID, somSelf->GetHeap(ev));
  2485.         versionNameProperty = CMRegisterProperty(cmContainer, versionName);
  2486.         
  2487.         versionObject = CMGetNextObjectWithProperty(cmContainer, kODNULL, versionNameProperty);
  2488.         version = CMUseValue(versionObject, versionDataProperty, versionDataType);
  2489.     
  2490.         CMSetValueRefCon(version, kODNULL);
  2491.         
  2492.         // Save the outermost container for embedded container creation.
  2493.         ODSessionRefCon* sessionRefCon = (ODSessionRefCon*) CMGetSessionRefCon(cmContainer);
  2494.         sessionRefCon->container = _fDocument->GetContainer(ev);
  2495.     
  2496. #ifdef ODDebug_CMDraft
  2497.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2498.     somPrintf("OpenVersion: CMDocument %x DraftID %d IsNewDraft %d versionID %d prevVersionID %d\n", tempDoc, somSelf->GetID(ev), somSelf->IsNewDraft(ev), _fVersionID, _fPrevVersionID);    
  2499. #endif
  2500.         ODEmbeddedContainerID    containerID;
  2501.         containerID.cmValue = version;
  2502.         containerID.shouldMerge = kODFalse;
  2503.         ODByteArray*    ba = CreateByteArray(&containerID, sizeof(ODEmbeddedContainerID));
  2504.         _fEmbeddedContainer = (ODEmbeddedContainer*)
  2505.             _fDocument->GetContainer(ev)->GetStorageSystem(ev)->AcquireContainer(ev, kODBentoEmbeddedContainer, ba);
  2506.         DisposeByteArray(ba);
  2507.     
  2508.         if (versionName != kODNULL)
  2509.             ODDisposePtr(versionName);
  2510.         if (oldVersionName != kODNULL)
  2511.             ODDisposePtr(oldVersionName);
  2512.             
  2513.         ODSessionRestoreCMAllocReserve(cmContainer);
  2514.  
  2515.         somSelf->OpenCollections(ev);
  2516.     }
  2517.     else
  2518.         THROW(kODErrInvalidPermissions);
  2519.     
  2520.     SOM_CATCH_ALL
  2521.     SOM_ENDTRY
  2522. }
  2523.  
  2524. //------------------------------------------------------------------------------
  2525. // CMDraft: CloseVersion
  2526. //------------------------------------------------------------------------------
  2527.  
  2528. extern void ODBentoFatalError(ODBoolean allowSuppress); // SessHdr.cpp
  2529.  
  2530. SOM_Scope void  SOMLINK CMDraftCloseVersion(CMDraft *somSelf, Environment *ev)
  2531. {
  2532.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2533.     CMDraftMethodDebug("CMDraft","CloseVersion");
  2534.     
  2535.     SOM_TRY
  2536.  
  2537. #ifdef ODDebug_CMDraft
  2538.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2539.     somPrintf("CloseVersion: CMDocument %x DraftID %d versionID %d Permission %d\n", tempDoc, somSelf->GetID(ev), _fVersionID, _fPermissions);    
  2540. #endif
  2541.  
  2542.     if (_fPermissions == kODDPExclusiveWrite) {
  2543.         VersionList*    versionList = kODNULL;
  2544.  
  2545.         versionList = _fDocument->TestAndGetVersionList(ev);
  2546.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2547.     
  2548.         if (versionList->IsBelow(_fOrigTopVersionDraftID, versionList->GetSameVersionDraftID(_fID)))
  2549.             _fEmbeddedContainer->SetMergeFlag(ev, kODFalse);
  2550.         somSelf->CloseCollections(ev);
  2551.     }
  2552.     else {
  2553.         somSelf->DeleteCollections(ev);
  2554.         somSelf->CreateCollections(ev);
  2555.     }
  2556.     
  2557.     if (_fEmbeddedContainer != kODNULL) {
  2558.         // In order to prevent closing errors from being eaten silently inside
  2559.         // Release(), we are going to close the embedded container first.  This
  2560.         // is necessary so that closing errors will propagate up to
  2561.         // CMDraft::Close() (called from either CMDocument::ReleaseDraft() or
  2562.         // CMDocument::SaveToAPrevDraft()).  Otherwise, the bogus draft (with
  2563.         // an invalid Bento label) will be blessed by externalizing its id
  2564.         // in the new draft version list, which would corrupt the document.
  2565.         // Note that we have made sure that closing the embedded container a
  2566.         // second time in Release() is silently harmless.
  2567.         
  2568.         _fEmbeddedContainer->Close(ev);
  2569.         
  2570.         _fEmbeddedContainer->Release(ev);
  2571.         _fEmbeddedContainer = kODNULL;
  2572.     }
  2573.     
  2574.     _fIsNewDraft = kODFalse;
  2575.     
  2576.     SOM_CATCH_ALL
  2577.         
  2578.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  2579.         
  2580.     SOM_ENDTRY
  2581. }
  2582.  
  2583. //------------------------------------------------------------------------------
  2584. // CMDraft: DestroyVersion
  2585. //------------------------------------------------------------------------------
  2586.  
  2587. SOM_Scope void  SOMLINK CMDraftDestroyVersion(CMDraft *somSelf, Environment *ev)
  2588. {
  2589.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2590.     CMDraftMethodDebug("CMDraft","DestroyVersion");
  2591.     
  2592. #ifdef ODDebug_CMDraft
  2593.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2594.     somPrintf("Destroy Version: CMDocument %x DraftID %d versionID %d Permission %d\n", tempDoc, somSelf->GetID(ev), _fVersionID, _fPermissions);    
  2595. #endif
  2596.     
  2597.     if (_fPermissions == kODDPExclusiveWrite) {
  2598.         SOM_TRY
  2599.     
  2600.         somSelf->DeleteCollections(ev);
  2601.         somSelf->CreateCollections(ev);
  2602.     
  2603.         if (_fEmbeddedContainer != kODNULL) {
  2604.             _fEmbeddedContainer->Abort(ev);
  2605.             CMObject        parentObject = kODNULL;
  2606.             ODByteArray     ba = _fEmbeddedContainer->GetID(ev);
  2607.             CMValue parentValue = *((CMValue*) ba._buffer);
  2608.             ODDisposePtr(ba._buffer);
  2609.  
  2610.             CMContainer cmContainer = somSelf->GetCMContainer(ev);
  2611.             ODSessionMustHaveCMAllocReserve(cmContainer);
  2612.             
  2613.             CMGetValueInfo(parentValue, kODNULL, &parentObject,
  2614.                             kODNULL, kODNULL, kODNULL);
  2615.             CMDeleteValue(parentValue);
  2616.             CMDeleteObject(parentObject);
  2617.  
  2618.             ODSessionRestoreCMAllocReserve(cmContainer);
  2619.             
  2620.             _fEmbeddedContainer->Release(ev);
  2621.             _fEmbeddedContainer = kODNULL;
  2622.         }
  2623.         
  2624.         SOM_CATCH_ALL
  2625.         SOM_ENDTRY
  2626.     }
  2627. }
  2628.  
  2629. //------------------------------------------------------------------------------
  2630. // CMDraft: FlushVersion
  2631. //------------------------------------------------------------------------------
  2632.  
  2633. SOM_Scope void  SOMLINK CMDraftFlushVersion(CMDraft *somSelf, Environment *ev)
  2634. {
  2635.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2636.     CMDraftMethodDebug("CMDraft","FlushVersion");
  2637.  
  2638. }
  2639.  
  2640. //------------------------------------------------------------------------------
  2641. // CMDraft: Reinitialize
  2642. //------------------------------------------------------------------------------
  2643.  
  2644. SOM_Scope void  SOMLINK CMDraftReinitialize(CMDraft *somSelf, Environment *ev,
  2645.         ODDraftPermissions perms)
  2646. {
  2647.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2648.     CMDraftMethodDebug("CMDraft","Reinitialize");
  2649.     
  2650.     SOM_TRY
  2651.  
  2652.     if ((perms == kODDPExclusiveWrite) &&
  2653.         (_fEmbeddedContainer != kODNULL) &&
  2654.         (_fEmbeddedContainer->GetUseMode(ev) & kCMReading)) {
  2655.         MyDebugStr("Reinitialize.\n");
  2656.         THROW(kODErrInvalidPermissions);
  2657.     }
  2658.     
  2659.     // Close this version first
  2660.     
  2661.     // somSelf->CloseVersion(ev);
  2662.     
  2663.     // Set the permissions
  2664.     
  2665.     _fPermissions = perms;
  2666.  
  2667.     // Open or create a new version
  2668.  
  2669.     if (_fEmbeddedContainer == kODNULL) {
  2670. #if lazyOpen
  2671.         _fExternalized = kODFalse;
  2672. #else
  2673.         if (_fPermissions == kODDPReadOnly)
  2674.             somSelf->OpenVersion(ev);
  2675.         else
  2676.             somSelf->CreateVersion(ev);
  2677. #endif
  2678.     }
  2679.     
  2680.     //_fDocument->Reopen(ev);
  2681.     
  2682.     SOM_CATCH_ALL
  2683.     SOM_ENDTRY
  2684. }
  2685.  
  2686. //------------------------------------------------------------------------------
  2687. // CMDraft: Open
  2688. //------------------------------------------------------------------------------
  2689.  
  2690. SOM_Scope void  SOMLINK CMDraftOpen(CMDraft *somSelf, Environment *ev)
  2691. {
  2692.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2693.     CMDraftMethodDebug("CMDraft","Open");
  2694.  
  2695.     SOM_TRY
  2696.  
  2697.     if (_fEmbeddedContainer == kODNULL) {
  2698. #if lazyOpen
  2699.         _fExternalized = kODFalse;
  2700. #else
  2701.         if (_fPermissions == kODDPReadOnly)
  2702.             somSelf->OpenVersion(ev);
  2703.         else
  2704.             somSelf->CreateVersion(ev);
  2705. #endif
  2706.     }
  2707.  
  2708.     SOM_CATCH_ALL
  2709.     SOM_ENDTRY
  2710. }
  2711.  
  2712. #pragma segment CMDraft2
  2713.  
  2714. //------------------------------------------------------------------------------
  2715. // CMDraft: Close
  2716. //------------------------------------------------------------------------------
  2717.  
  2718. SOM_Scope void  SOMLINK CMDraftClose(CMDraft *somSelf, Environment *ev)
  2719. {
  2720.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2721.     CMDraftMethodDebug("CMDraft","Close");
  2722.  
  2723.     SOM_TRY
  2724.  
  2725. #if ODDebug_Drafts
  2726.     somPrintf("CMDraftClose: %d\n", somSelf->GetID(ev));
  2727. #endif
  2728.  
  2729. #if lazyOpen
  2730.     if (_fEmbeddedContainer != kODNULL) {
  2731.  
  2732.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  2733.         ODSessionMustHaveCMAllocReserve(cmContainer);
  2734.         // AcquireDraftPropertiesObject() makes CM calls:
  2735.  
  2736.         CMObject draftPropertiesObject = AcquireDraftPropertiesObject(somSelf->GetCMContainer(ev));
  2737.         if (draftPropertiesObject == kODNULL)
  2738.             THROW(kODErrNoDraftProperties);
  2739.         
  2740.         CMKeepObject(draftPropertiesObject);
  2741.         
  2742.         ODSessionRestoreCMAllocReserve(cmContainer);
  2743.         
  2744.         somSelf->CloseVersion(ev);
  2745.     }
  2746. #else
  2747.     somSelf->CloseVersion(ev);
  2748. #endif
  2749.  
  2750.     SOM_CATCH_ALL
  2751.     SOM_ENDTRY
  2752. }
  2753.  
  2754. //------------------------------------------------------------------------------
  2755. // CMDraft: Abort
  2756. //------------------------------------------------------------------------------
  2757.  
  2758. SOM_Scope void  SOMLINK CMDraftAbort(CMDraft *somSelf, Environment *ev)
  2759. {
  2760.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2761.     CMDraftMethodDebug("CMDraft","Abort");
  2762.  
  2763.     SOM_TRY
  2764.  
  2765.     if (_fPermissions == kODDPReadOnly)
  2766.         THROW(kODErrInvalidPermissions);
  2767.  
  2768.     if (_fDraftProperties != kODNULL) {
  2769.         _fDraftProperties->Release(ev);
  2770.         _fDraftProperties = kODNULL;
  2771.     }
  2772.  
  2773. #if TestFlushContainer
  2774.     if (_fRemoveChangeOnAbort) {
  2775.         VersionList*    versionList = kODNULL;
  2776.         
  2777.         versionList = _fDocument->TestAndGetVersionList(ev);
  2778.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2779.     
  2780.         TRY
  2781.             if (versionList->Exists(_fID) != kODFalse)
  2782.                 versionList->RemoveChanges(_fID);
  2783.             
  2784.         CATCH_ALL
  2785.         
  2786.             _fDocument->ReleaseVersionList(ev);
  2787.             RERAISE;
  2788.     
  2789.         ENDTRY
  2790.     }
  2791. #else
  2792.     _fDocument->InternalizeVersionList(ev);
  2793. #endif
  2794.     somSelf->DestroyVersion(ev);
  2795.     //    _fDocument->Reopen(ev);
  2796.     
  2797.     SOM_CATCH_ALL
  2798.     SOM_ENDTRY
  2799. }
  2800.  
  2801. //------------------------------------------------------------------------------
  2802. // CMDraft: Flush
  2803. //------------------------------------------------------------------------------
  2804.  
  2805. SOM_Scope void  SOMLINK CMDraftFlush(CMDraft *somSelf, Environment *ev)
  2806. {
  2807.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2808.     CMDraftMethodDebug("CMDraft","Flush");
  2809.  
  2810.     if (_fPermissions == kODDPExclusiveWrite) {
  2811.         SOM_TRY
  2812.             somSelf->FlushVersion(ev);
  2813.         SOM_CATCH_ALL
  2814.         SOM_ENDTRY
  2815.     }
  2816. }
  2817.  
  2818.  
  2819. //------------------------------------------------------------------------------
  2820. // CMDraft: IsNewDraft
  2821. //------------------------------------------------------------------------------
  2822.  
  2823. SOM_Scope ODBoolean  SOMLINK CMDraftIsNewDraft(CMDraft *somSelf, Environment *ev)
  2824. {
  2825.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2826.     CMDraftMethodDebug("CMDraft","IsNewDraft");
  2827.  
  2828.     return _fIsNewDraft;
  2829. }
  2830.  
  2831. //------------------------------------------------------------------------------
  2832. // CMDraft: GetEmbeddedContainer
  2833. //------------------------------------------------------------------------------
  2834.  
  2835. SOM_Scope ODEmbeddedContainer*  SOMLINK CMDraftGetEmbeddedContainer(CMDraft *somSelf, Environment *ev)
  2836. {
  2837.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2838.     CMDraftMethodDebug("CMDraft","GetEmbeddedContainer");
  2839.  
  2840. #if lazyOpen
  2841.     SOM_TRY
  2842.     if (_fEmbeddedContainer == kODNULL) {
  2843.         if (_fPermissions == kODDPReadOnly)
  2844.             somSelf->OpenVersion(ev);
  2845.         else
  2846.             somSelf->CreateVersion(ev);
  2847.     }
  2848.     SOM_CATCH_ALL
  2849.     SOM_ENDTRY
  2850. #endif
  2851.  
  2852.     return _fEmbeddedContainer;
  2853. }
  2854.  
  2855. //------------------------------------------------------------------------------
  2856. // CMDraft: GetCMContainer
  2857. //------------------------------------------------------------------------------
  2858.  
  2859. SOM_Scope CMContainer  SOMLINK CMDraftGetCMContainer(CMDraft *somSelf, Environment *ev)
  2860. {
  2861.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2862.     CMDraftMethodDebug("CMDraft","GetCMContainer");
  2863.     
  2864.     SOM_TRY
  2865.  
  2866. #if lazyOpen
  2867.     if (_fEmbeddedContainer == kODNULL) {
  2868.         if (_fPermissions == kODDPReadOnly)
  2869.             somSelf->OpenVersion(ev);
  2870.         else
  2871.             somSelf->CreateVersion(ev);
  2872.     }
  2873. #endif
  2874.  
  2875.     if (_fEmbeddedContainer == kODNULL)
  2876.         THROW(kODErrCannotGetDraftVersion);
  2877.     return _fEmbeddedContainer->GetCMContainer(ev);
  2878.     
  2879.     SOM_CATCH_ALL
  2880.     SOM_ENDTRY
  2881.     return kODNULL;
  2882. }
  2883.  
  2884. //------------------------------------------------------------------------------
  2885. // AcquireDraftPropertiesObject
  2886. //------------------------------------------------------------------------------
  2887.  
  2888. // Callers must ODSessionMustHaveCMAllocReserve() first:
  2889.  
  2890. static CMObject AcquireDraftPropertiesObject(CMContainer container)
  2891. {
  2892.     CMObject        draftPropertiesObject = kODNULL;
  2893.     CMType            rootSUType;
  2894.     CMProperty        rootSUProp;
  2895.     CMValue            rootSU;
  2896.     
  2897.     CMContainerModeFlags    openMode;
  2898.  
  2899.     if ((rootSUType = CMRegisterType(container, kODStorageUnitType)) == kODNULL)
  2900.         THROW(kODErrBentoInvalidType);
  2901.     if ((rootSUProp = CMRegisterProperty(container, kODPropRootSU)) == kODNULL)
  2902.         THROW(kODErrBentoInvalidProperty);
  2903.     draftPropertiesObject = CMGetNextObjectWithProperty(container, kODNULL, rootSUProp);
  2904.     
  2905.     if (draftPropertiesObject == kODNULL) {
  2906.         
  2907.         CMGetContainerInfo(container, kODNULL, kODNULL, kODNULL, kODNULL, &openMode);
  2908.         if (openMode == kCMReading)
  2909.             return kODNULL;
  2910.         
  2911.         draftPropertiesObject = CMNewObject(container);
  2912.  
  2913.         if ((rootSU = CMNewValue(draftPropertiesObject, rootSUProp, rootSUType)) == kODNULL)
  2914.             THROW(kODErrBentoCannotNewValue);
  2915.         CMWriteValueData(rootSU, "", 0, 0);
  2916.     }
  2917.     
  2918.     return draftPropertiesObject;
  2919. }
  2920.  
  2921. //------------------------------------------------------------------------------
  2922. // GetVersionNameFromVersionID
  2923. //------------------------------------------------------------------------------
  2924.  
  2925. static ODType GetVersionNameFromVersionID(ODVersionID id, ODMemoryHeapID heapID)
  2926. {
  2927.     ODSByte*    versionName = kODNULL;
  2928.     ODSByte    cString[kMaxStringSize];
  2929.         
  2930.     if (id != 0) {
  2931.         itoa(id, cString);
  2932.         versionName = (ODSByte*) ODNewPtr(strlen(kODVersionNamePrefix) + strlen(cString) + 1, heapID);
  2933.         strcpy(versionName, kODVersionNamePrefix);
  2934.         strcat(versionName, cString);
  2935.     }
  2936.     return versionName;
  2937. }
  2938.  
  2939. //------------------------------------------------------------------------------
  2940. // CMDraft: RetrievePersistentObject
  2941. //------------------------------------------------------------------------------
  2942.  
  2943. SOM_Scope ODPersistentObject*  SOMLINK CMDraftRetrievePersistentObject(CMDraft *somSelf, Environment *ev,
  2944.         ODStorageUnitID id)
  2945. {
  2946.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2947.     CMDraftMethodDebug("CMDraft","RetrievePersistentObject");
  2948.  
  2949.     ODPersistentObject*    object = kODNULL;
  2950.     
  2951.     SOM_TRY
  2952.     
  2953.     if (_fPersistentObjects->GetValue(&id, &object))
  2954.         object->Acquire(ev);
  2955.     
  2956.     SOM_CATCH_ALL
  2957.     SOM_ENDTRY
  2958.     return object;
  2959. }
  2960.  
  2961. //------------------------------------------------------------------------------
  2962. // CMDraft: ReleasePersistentObject
  2963. //------------------------------------------------------------------------------
  2964.  
  2965. SOM_Scope void  SOMLINK CMDraftReleasePersistentObject(CMDraft *somSelf, Environment *ev,
  2966.         ODPersistentObject* object)
  2967. {
  2968. //  CMDraftData *somThis = CMDraftGetData(somSelf);
  2969.     CMDraftMethodDebug("CMDraft","ReleasePersistentObject");
  2970.     
  2971.     SOM_TRY
  2972.     
  2973.     if (object->GetRefCount(ev) != 0)
  2974.         THROW(kODErrRefCountGreaterThanZero);
  2975.     
  2976.     SOM_CATCH_ALL
  2977.     SOM_ENDTRY
  2978. }
  2979.  
  2980. //------------------------------------------------------------------------------
  2981. // CMDraft: RemovePersistentObject
  2982. //------------------------------------------------------------------------------
  2983.  
  2984. SOM_Scope void  SOMLINK CMDraftRemovePersistentObject(CMDraft *somSelf, Environment *ev,
  2985.         ODPersistentObject* object)
  2986. {
  2987.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2988.     CMDraftMethodDebug("CMDraft","RemovePersistentObject");
  2989.     
  2990.     SOM_TRY
  2991.  
  2992.     ODStorageUnit*        su = object->GetStorageUnit(ev);
  2993.     ODStorageUnitID        id = object->GetID(ev);
  2994.     CMObject            cmObject = kODNULL;
  2995.     
  2996.     if (id == kODNULLID)
  2997.         THROW(kODErrInvalidPersistentObjectID);
  2998.         
  2999.     object->Release(ev);
  3000.  
  3001.     if (object->GetRefCount(ev) != 0)
  3002.         THROW(kODErrRefCountGreaterThanZero);
  3003.  
  3004.     if ((su != kODNULL) && (su->GetRefCount(ev) != 1))
  3005.         THROW(kODErrRefCountNotEqualOne);
  3006.  
  3007.     object->ReleaseAll(ev);
  3008.  
  3009.     _fPersistentObjects->RemoveEntry(&id);
  3010.     delete object;
  3011.     
  3012.     _fStorageUnits->RemoveEntry(&id);
  3013.     delete su;
  3014.  
  3015.     if (_fIDList->Exists(id) != kODFalse) {
  3016.         cmObject = (CMObject) _fIDList->Get(id);
  3017.         _fIDList->Remove(id);
  3018.  
  3019.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  3020.         ODSessionMustHaveCMAllocReserve(cmContainer);
  3021.  
  3022.         if (cmObject != kODNULL)
  3023.             CMDeleteObject(cmObject);
  3024.  
  3025.         ODSessionRestoreCMAllocReserve(cmContainer);
  3026.     }
  3027.  
  3028.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  3029.     
  3030.     SOM_CATCH_ALL
  3031.     SOM_ENDTRY
  3032. }
  3033.  
  3034. //------------------------------------------------------------------------------
  3035. // CMDraft: CreateCollections
  3036. //------------------------------------------------------------------------------
  3037.  
  3038. SOM_Scope void  SOMLINK CMDraftCreateCollections(CMDraft *somSelf, Environment *ev)
  3039. {
  3040.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3041.     CMDraftMethodDebug("CMDraft","CreateCollections");
  3042.     
  3043.     SOM_TRY
  3044.  
  3045.     ODMemoryHeapID heap = somSelf->GetHeap(ev);
  3046.  
  3047.     _fPersistentObjects = new(heap) 
  3048.         OpenHashTable(OpenHashTable::StdEqual,
  3049.                       OpenHashTable::StdHash, heap);
  3050.     _fPersistentObjects->Initialize(kODInitialNumEntries,
  3051.                                     sizeof(ODStorageUnitID),
  3052.                                     sizeof(ODPersistentObject*));
  3053.  
  3054.     _fStorageUnits = new(heap) 
  3055.         OpenHashTable(OpenHashTable::StdEqual,
  3056.                       OpenHashTable::StdHash, heap);
  3057.     _fStorageUnits->Initialize(kODInitialNumEntries,
  3058.                                sizeof(ODStorageUnitID),
  3059.                                sizeof(ODStorageUnit*));
  3060.  
  3061.     _fIDList = new(somSelf->GetHeap(ev)) IDList;
  3062.     _fIDList->Initialize();
  3063.     
  3064.     SOM_CATCH_ALL
  3065.     SOM_ENDTRY
  3066. }
  3067.  
  3068. //------------------------------------------------------------------------------
  3069. // CMDraft: DeleteCollections
  3070. //------------------------------------------------------------------------------
  3071.  
  3072. SOM_Scope void  SOMLINK CMDraftDeleteCollections(CMDraft *somSelf, Environment *ev)
  3073. {
  3074.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3075.     CMDraftMethodDebug("CMDraft","DeleteCollections");
  3076.     
  3077.     SOM_TRY
  3078.  
  3079.     if (_fDraftProperties != kODNULL)
  3080.     {
  3081.         _fDraftProperties->Release(ev);
  3082.         _fDraftProperties = kODNULL;
  3083.     }
  3084.     if (_fPersistentObjects != kODNULL) {
  3085.         ODStorageUnitID        id;
  3086.         ODPersistentObject*    object;
  3087.         OpenHashTableIterator    iter(_fPersistentObjects);
  3088.         
  3089.         for (iter.First(&id, &object); iter.IsNotComplete(); iter.Next(&id, &object)) {
  3090.             if (object != kODNULL) {
  3091.                 SOM_TRY
  3092.                     object->ReleaseAll(ev);
  3093.                 SOM_CATCH_ALL
  3094.                     WARN("Exception thrown by object %x ID %x error %d\n", object, object->GetID(ev), ErrorCode());
  3095.                 SOM_ENDTRY
  3096.             }
  3097.         }
  3098.         
  3099.         for (iter.First(&id, &object); iter.IsNotComplete(); iter.Next(&id, &object)) {
  3100.             if (object != kODNULL) {
  3101.                 delete object;
  3102.             }
  3103.         }
  3104.         delete _fPersistentObjects;
  3105.         _fPersistentObjects = kODNULL;
  3106.     }
  3107.  
  3108.     if (_fStorageUnits != kODNULL) {
  3109.         ODStorageUnitID        id;
  3110.         ODStorageUnit*            su;
  3111.         OpenHashTableIterator    iter(_fStorageUnits);
  3112.         for (iter.First(&id, &su); iter.IsNotComplete(); iter.Next(&id, &su)) {
  3113.             if (su != kODNULL) {
  3114.                 delete su;
  3115.             }
  3116.         }
  3117.         delete _fStorageUnits;
  3118.         _fStorageUnits = kODNULL;
  3119.         _fDraftProperties = kODNULL;
  3120.     }
  3121.     
  3122.     ODDeleteObject(_fIDList);
  3123.     
  3124.     SOM_CATCH_ALL
  3125.     SOM_ENDTRY
  3126. }
  3127.  
  3128. //------------------------------------------------------------------------------
  3129. // CMDraft: ExternalizeCollections
  3130. //------------------------------------------------------------------------------
  3131.  
  3132. SOM_Scope void  SOMLINK CMDraftExternalizeCollections(CMDraft *somSelf, Environment *ev)
  3133. {
  3134.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3135.     CMDraftMethodDebug("CMDraft","ExternalizeCollections");
  3136.     
  3137.     SOM_TRY
  3138.  
  3139.     ODID                    id;
  3140.     ODStorageUnit*            su;
  3141.  
  3142.     OpenHashTableIterator    persistentObjects(_fPersistentObjects);
  3143.     ODPersistentObject*    object;
  3144.     
  3145.     for (persistentObjects.First(&id, &object);
  3146.             persistentObjects.IsNotComplete();
  3147.             persistentObjects.Next(&id, &object)) {
  3148.         // Temporarily bump the refcount to make sure that the object is
  3149.         // in a valid state.
  3150.         object->Acquire(ev);
  3151.         TempODRefCntObject tempObject = object; // ensure it's released
  3152.         su = object->GetStorageUnit(ev);
  3153.         if ((su != kODNULL) && (su->Exists(ev, kODNULL, kODNULL, 0) != kODFalse))
  3154.         object->Externalize(ev);
  3155.     }
  3156.  
  3157.     OpenHashTable            suCollection(*_fStorageUnits);
  3158.     suCollection.InitAndCopyFrom(*_fStorageUnits);
  3159.     OpenHashTableIterator    storageUnits(&suCollection);
  3160.  
  3161.     for (storageUnits.First(&id, &su);
  3162.             storageUnits.IsNotComplete();
  3163.             storageUnits.Next(&id, &su)) {
  3164.         // Temporarily bump the refcount to make sure that the object is
  3165.         // in a valid state.
  3166.         su->Acquire(ev);
  3167.         TempODStorageUnit tempSU = su; // ensure it's released
  3168.         if (su->Exists(ev, kODNULL, kODNULL, 0) != kODFalse)
  3169.             su->Externalize(ev);
  3170.     }
  3171.     
  3172.     SOM_CATCH_ALL
  3173.     SOM_ENDTRY
  3174. }
  3175.  
  3176. //------------------------------------------------------------------------------
  3177. // CMDraft: CloseCollections
  3178. //------------------------------------------------------------------------------
  3179.  
  3180. SOM_Scope void  SOMLINK CMDraftCloseCollections(CMDraft *somSelf, Environment *ev)
  3181. {
  3182.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3183.     CMDraftMethodDebug("CMDraft","CloseCollections");
  3184.     
  3185.     SOM_TRY
  3186.     
  3187.     somSelf->FailIfNotExclusiveWrite(ev);
  3188.     
  3189.     // dh - It would be nice if these Purge methods didn't need to be called
  3190.     // under non-low mem situations. Since these functions allocate memory,
  3191.     // it really exaserbates our already bad memory situation.
  3192.     somSelf->Purge(ev, 0);
  3193.     PurgeAllStorageUnits(ev, _fStorageUnits, _fIDList); // purge SU, relase CMObjects
  3194.     
  3195.     SOM_CATCH_ALL
  3196.     SOM_ENDTRY
  3197. }
  3198.  
  3199. //------------------------------------------------------------------------------
  3200. // CMDraft: OpenCollections
  3201. //------------------------------------------------------------------------------
  3202.  
  3203. SOM_Scope void  SOMLINK CMDraftOpenCollections(CMDraft *somSelf, Environment *ev)
  3204. {
  3205.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3206.     CMDraftMethodDebug("CMDraft","OpenCollections");
  3207.     
  3208.     SOM_TRY
  3209.  
  3210.     OpenHashTableIterator    storageUnits(_fStorageUnits);
  3211.     
  3212.     ODID                    id;
  3213.     ODStorageUnit*            su;
  3214.  
  3215.     for (storageUnits.First(&id, &su);
  3216.             storageUnits.IsNotComplete();
  3217.             storageUnits.Next(&id, &su)) {
  3218.         su->Internalize(ev);
  3219.     }
  3220.     
  3221.     SOM_CATCH_ALL
  3222.     SOM_ENDTRY
  3223. }
  3224.  
  3225. //------------------------------------------------------------------------------
  3226. // CMDraft: AreEmptyCollections
  3227. //------------------------------------------------------------------------------
  3228.  
  3229. SOM_Scope ODBoolean  SOMLINK CMDraftAreEmptyCollections(CMDraft *somSelf, Environment *ev)
  3230. {
  3231.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3232.     CMDraftMethodDebug("CMDraft","AreEmptyCollections");
  3233.     
  3234.     SOM_TRY
  3235.  
  3236.     OpenHashTableIterator    storageUnits(_fStorageUnits);
  3237.     OpenHashTableIterator    persistentObjects(_fPersistentObjects);
  3238.     ODID                    id;
  3239.     ODPersistentObject*    object;
  3240.     ODStorageUnit*            su;
  3241.     
  3242.     for (persistentObjects.First(&id, &object);
  3243.             persistentObjects.IsNotComplete();
  3244.             persistentObjects.Next(&id, &object)) {
  3245.         if (object->GetRefCount(ev) > 0)
  3246.             return kODFalse;
  3247.     }
  3248.  
  3249.     for (storageUnits.First(&id, &su); storageUnits.IsNotComplete(); storageUnits.Next(&id, &su)) {
  3250.         if (su->GetRefCount(ev) > 0)
  3251.             return kODFalse;
  3252.     }
  3253.     
  3254.     SOM_CATCH_ALL
  3255.     SOM_ENDTRY
  3256.         
  3257.     return kODTrue;
  3258. }
  3259.  
  3260. //------------------------------------------------------------------------------
  3261. // CMDraft: NeedExternalizing
  3262. //------------------------------------------------------------------------------
  3263.  
  3264. SOM_Scope ODBoolean  SOMLINK CMDraftNeedExternalizing(CMDraft *somSelf, Environment *ev)
  3265. {
  3266.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3267.     CMDraftMethodDebug("CMDraft","NeedExternalizing");
  3268.  
  3269.     return _fExternalized;
  3270. }
  3271.  
  3272.  
  3273. //------------------------------------------------------------------------------
  3274. // CMDraft: GetIDList
  3275. //------------------------------------------------------------------------------
  3276.  
  3277. SOM_Scope IDList*  SOMLINK CMDraftGetIDList(CMDraft *somSelf, Environment *ev)
  3278. {
  3279.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3280.     CMDraftMethodDebug("CMDraft","GetIDList");
  3281.  
  3282.     return _fIDList;
  3283. }
  3284.  
  3285. //------------------------------------------------------------------------------
  3286. // CMDraft: IsChangedFromPrev
  3287. //------------------------------------------------------------------------------
  3288.  
  3289. SOM_Scope ODBoolean  SOMLINK CMDraftIsChangedFromPrev(CMDraft *somSelf, Environment *ev,
  3290.         VersionList* versionList)
  3291. {
  3292.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3293.     CMDraftMethodDebug("CMDraft","IsChangedFromPrev");
  3294.  
  3295.     ODBoolean        changedFromPrev = kODFalse;
  3296.     ODVersionID    prevVersionID;
  3297.     ODDraftID        prevDraftID;
  3298.     
  3299.     // If this draft has been modified, return kODTrue.
  3300.     
  3301.     if (_fChangedFromPrev != kODFalse)
  3302.         return kODTrue;
  3303.  
  3304.     // versionList->ChangedFromPrev is accurate only when the draft is
  3305.     // opened read-only. Therefore, additional check is needed to ensure that
  3306.     // we don't return kODTrue even when the draft has not be changed.
  3307.  
  3308.     SOM_TRY
  3309.         changedFromPrev = versionList->ChangedFromPrev(_fID);
  3310.         
  3311.         if ((changedFromPrev != kODFalse) && (_fPermissions == kODDPExclusiveWrite)) {
  3312.             prevDraftID = versionList->GetPreviousDraftID(_fID);
  3313.             prevVersionID = versionList->GetDraft(prevDraftID);
  3314.             if (prevVersionID == _fPrevVersionID)
  3315.                 changedFromPrev = kODFalse;
  3316.         }
  3317.     SOM_CATCH_ALL
  3318.     SOM_ENDTRY
  3319.     
  3320.     return changedFromPrev;
  3321. }
  3322.  
  3323. //------------------------------------------------------------------------------
  3324. // CMDraft: BeginClone
  3325. //------------------------------------------------------------------------------
  3326.  
  3327. SOM_Scope ODDraftKey  SOMLINK CMDraftBeginClone(CMDraft *somSelf, Environment *ev,
  3328.         ODDraft* destDraft,
  3329.         ODFrame* destFrame,
  3330.         ODCloneKind kind)
  3331. {
  3332.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3333.     CMDraftMethodDebug("CMDraft","BeginClone");
  3334.  
  3335.     OpenHashTable* clonedSUIDs = kODNULL;        ODVolatile(clonedSUIDs);
  3336.     OpenHashTable* weakClonedSUIDs = kODNULL;    ODVolatile(weakClonedSUIDs);
  3337.     OpenHashTable* linksToCloneSUIDs = kODNULL;    ODVolatile(linksToCloneSUIDs);
  3338.  
  3339.     ODDraftKey result = 0;
  3340.  
  3341.     SOM_TRY
  3342.  
  3343.         // Allow beginning a new clone into a link if a clone from a link
  3344.         // is in progress; common if the link contains promises
  3345.         if ( (kind == kODCloneToLink) && (_fCloneKind == kODCloneFromLink) )
  3346.         {
  3347.             if ( _fLockCount > 1 )
  3348.                 THROW(kODErrCloningInProgress);
  3349.         }
  3350.         else if (_fLockCount > 0)
  3351.             THROW(kODErrCloningInProgress);
  3352.  
  3353. #ifdef DebugClone
  3354.         somPrintf("\nCMDraft::BeginClone - ");
  3355.         switch (kind)
  3356.         {
  3357.         case kODCloneCut:        somPrintf("Cut\n"); break;
  3358.         case kODCloneCopy:        somPrintf("Copy\n"); break;
  3359.         case kODClonePaste:        somPrintf("Paste\n"); break;
  3360.         case kODCloneDropCopy:    somPrintf("Drop Copy\n"); break;
  3361.         case kODCloneDropMove:    somPrintf("Drop Move\n"); break;
  3362.         case kODCloneToLink:    somPrintf("To Link\n"); break;
  3363.         case kODCloneFromLink:    somPrintf("From Link\n"); break;
  3364.         case kODCloneAll:        somPrintf("All\n"); break;
  3365.         case kODCloneToFile:    somPrintf("To File\n"); break;
  3366.         default:                somPrintf("Invalid clone kind!\n"); break;
  3367.         }
  3368. #endif
  3369.  
  3370.         // Validate the clone kind parameter
  3371.         switch (kind)
  3372.         {
  3373.         case kODClonePaste:
  3374.         case kODCloneDropCopy:
  3375.         case kODCloneDropMove:
  3376.         case kODCloneToFile:
  3377.             {
  3378.             ODCloneKind origCloneKind = GetOriginalCloneKind(ev, somSelf);
  3379.             if ( (origCloneKind != kODCloneCut) && (origCloneKind != kODCloneCopy) )
  3380.                 THROW(kODErrInconsistentCloneKind);
  3381.             }
  3382.             if ( somSelf == destDraft )
  3383.                 THROW(kODErrInvalidDestinationDraft);
  3384.             break;
  3385.     
  3386.         case kODCloneCut:
  3387.         case kODCloneCopy:
  3388.             if ( somSelf == destDraft )
  3389.                 THROW(kODErrInvalidDestinationDraft);
  3390.             break;
  3391.     
  3392.         case kODCloneToLink:
  3393.         case kODCloneFromLink:
  3394.             if ( somSelf != destDraft )
  3395.                 THROW(kODErrInvalidDestinationDraft);
  3396.             break;
  3397.     
  3398.         case kODCloneAll:
  3399.             break;
  3400.     
  3401.         default:
  3402.             THROW(kODErrInvalidCloneKind);
  3403.             break;
  3404.         }
  3405.     
  3406.         ODMemoryHeapID heap = somSelf->GetHeap(ev);
  3407.  
  3408.         // Ensure both hash tables can be allocated
  3409.         if ( _fLockCount == 0 )
  3410.         {
  3411.             clonedSUIDs = new(heap) 
  3412.                 OpenHashTable(OpenHashTable::StdEqual,
  3413.                               OpenHashTable::StdHash, heap);
  3414.             clonedSUIDs->Initialize(kInitialHashTableEntries,
  3415.                                       sizeof(ODStorageUnitID),
  3416.                                       sizeof(ODStorageUnitID));
  3417.             
  3418.             if ( (kind == kODCloneCut) || (kind == kODCloneCopy) )
  3419.                 ReadClonedObjectTable(ev, clonedSUIDs, destDraft);
  3420.  
  3421.             if ( (kind == kODCloneDropCopy) ||
  3422.                  (kind == kODCloneDropMove) ||
  3423.                  (kind == kODClonePaste)    ||
  3424.                  (kind == kODCloneToFile) )
  3425.             {
  3426.                 if ( GetOriginalDraft(ev, somSelf) == kODNULL )
  3427.                 {
  3428.                     // Clone is from a document draft to a document draft,
  3429.                     // so create the table for deferred strong clones
  3430.                     linksToCloneSUIDs = new(heap) 
  3431.                         OpenHashTable(OpenHashTable::StdEqual,
  3432.                                       OpenHashTable::StdHash, heap);
  3433.                     linksToCloneSUIDs->Initialize(kInitialHashTableEntries,
  3434.                                               sizeof(ODStorageUnitID),
  3435.                                               sizeof(ODStorageUnitID));
  3436.                 }
  3437.             }
  3438.         }
  3439.  
  3440.         weakClonedSUIDs = new(heap) 
  3441.             OpenHashTable(OpenHashTable::StdEqual,
  3442.                           OpenHashTable::StdHash, heap);
  3443.         weakClonedSUIDs->Initialize(kInitialHashTableEntries,
  3444.                                       sizeof(ODStorageUnitID),
  3445.                                       sizeof(ODStorageUnitID));
  3446.  
  3447.         // BeginClone must not fail beyond this point
  3448.  
  3449.         _fLockCount++;
  3450.     
  3451.         if ( _fLockCount == 1 )
  3452.         {
  3453.             _fCurrentKey++;
  3454.             _fCloneKind = kind;
  3455.             _fDestDraft = destDraft;
  3456.             _fDestFrame = destFrame;
  3457.             
  3458.             _fAnyFrameCloned = kODFalse;
  3459.             _fRootPartReused = kODFalse;
  3460.         
  3461.             _fClonedSUIDs = clonedSUIDs;
  3462.             _fLinksToCloneSUIDs = linksToCloneSUIDs;
  3463.         }
  3464.     
  3465.         _fSavedWeakClonedSUIDs = _fWeakClonedSUIDs;
  3466.         _fWeakClonedSUIDs = weakClonedSUIDs;
  3467.         
  3468.         result = _fCurrentKey;
  3469.  
  3470.     SOM_CATCH_ALL
  3471.     
  3472.         ODDeleteObject(clonedSUIDs);
  3473.         ODDeleteObject(linksToCloneSUIDs);
  3474.         ODDeleteObject(weakClonedSUIDs);
  3475.  
  3476.     SOM_ENDTRY
  3477.     
  3478.     return result;
  3479. }
  3480.  
  3481. //------------------------------------------------------------------------------
  3482. // CMDraft: GetClonedSUIDs
  3483. //------------------------------------------------------------------------------
  3484.  
  3485. SOM_Scope OpenHashTable*  SOMLINK CMDraftGetClonedSUIDs(CMDraft *somSelf, Environment *ev,
  3486.         ODDraft* destDraft)
  3487. {
  3488.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3489.     CMDraftMethodDebug("CMDraft","GetClonedSUIDs");
  3490.  
  3491.     if ((_fDestDraft != kODNULL) && (_fDestDraft != destDraft)) {
  3492.         ODDeleteObject(_fClonedSUIDs);
  3493.         ODDeleteObject(_fWeakClonedSUIDs);
  3494.         ODSetSOMException(ev,kODErrInvalidDestinationDraft);
  3495.         return kODNULL;
  3496.     }
  3497.     _fDestDraft = destDraft;
  3498.     
  3499.     return _fClonedSUIDs;    
  3500. }
  3501.  
  3502. //------------------------------------------------------------------------------
  3503. // CMDraft: EndClone
  3504. //------------------------------------------------------------------------------
  3505.  
  3506. SOM_Scope void  SOMLINK CMDraftEndClone(CMDraft *somSelf, Environment *ev,
  3507.         ODDraftKey key)
  3508. {
  3509.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3510.     CMDraftMethodDebug("CMDraft","EndClone");
  3511.  
  3512.     ODStorageUnitID        fromID;
  3513.     ODStorageUnitID        toID;
  3514.  
  3515.     SOM_TRY
  3516.  
  3517.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  3518.         THROW(kODErrInvalidDraftKey);
  3519.  
  3520.     somSelf->DoDeferredClones(ev, key);
  3521.  
  3522.     OpenHashTableIterator iter(_fWeakClonedSUIDs);
  3523.     for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID)) {
  3524.         if (toID != 0) {
  3525.             ODStorageUnit* toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  3526.             PRINT_CLONE("Removing weakly cloned ID %d (%d)\n", toID, ((CMStorageUnit*) toSU)->GetObjectID(ev));
  3527.             _fDestDraft->RemoveStorageUnit(ev, toSU);
  3528.         }
  3529.     }
  3530.  
  3531.     switch (_fCloneKind)
  3532.     {
  3533.     case kODCloneCopy:
  3534.     case kODCloneCut:
  3535.         SetOriginalDraft(ev, _fDestDraft, somSelf);
  3536.         if ( !OriginalCloneKindExists(ev, _fDestDraft) )
  3537.             SetOriginalCloneKind(ev, _fDestDraft, _fCloneKind);
  3538.         WriteClonedObjectTable(ev, _fClonedSUIDs, _fDestDraft);
  3539.         break;
  3540.     
  3541.     case kODClonePaste:
  3542.     case kODCloneDropCopy:
  3543.     case kODCloneDropMove:
  3544.     case kODCloneToFile:
  3545.         if ( (_fCloneKind == kODClonePaste) && (GetOriginalCloneKind(ev, somSelf) == kODCloneCut) )
  3546.             SetOriginalCloneKind(ev, somSelf, kODCloneCopy);
  3547.         break;
  3548.  
  3549.     default:
  3550.         break;
  3551.     }
  3552.  
  3553.     if ( somSelf->GetCloneKind(ev) == kODCloneDropMove )
  3554.     {
  3555.         if ( GetOriginalDraft(ev, somSelf) == _fDestDraft )
  3556.         {
  3557.             if ( _fAnyFrameCloned )
  3558.             {
  3559.                 if ( somSelf->ContainingPartInClone(ev, _fDestFrame) )
  3560.                     THROW(kODErrMoveIntoSelf);
  3561.             }
  3562.         }
  3563.     }
  3564.  
  3565.     --_fLockCount;
  3566.     
  3567.     if ( _fLockCount == 0 )
  3568.     {
  3569.         _fDestDraft = kODNULL;
  3570.         _fDestFrame = kODNULL;
  3571.     
  3572.         ODDeleteObject(_fClonedSUIDs);
  3573.         ODDeleteObject(_fLinksToCloneSUIDs);
  3574.     }
  3575.  
  3576.     ODDeleteObject(_fWeakClonedSUIDs);
  3577.     _fWeakClonedSUIDs = _fSavedWeakClonedSUIDs;
  3578.  
  3579.     PRINT_CLONE("CMDraft::EndClone - Clone completed\n\n");
  3580.  
  3581.     SOM_CATCH_ALL
  3582.     SOM_ENDTRY
  3583. }
  3584.  
  3585. //------------------------------------------------------------------------------
  3586. // CMDraft: AbortClone
  3587. //------------------------------------------------------------------------------
  3588.  
  3589. SOM_Scope void  SOMLINK CMDraftAbortClone(CMDraft *somSelf, Environment *ev,
  3590.         ODDraftKey key)
  3591. {
  3592.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3593.     CMDraftMethodDebug("CMDraft","AbortClone");
  3594.  
  3595.     SOM_TRY
  3596.  
  3597. #if ODDebug_Drafts
  3598.     somPrintf("CMDraftAbort: %d\n", somSelf->GetID(ev));
  3599. #endif
  3600.  
  3601.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  3602.         THROW(kODErrInvalidDraftKey);
  3603.  
  3604.     --_fLockCount;
  3605.  
  3606.     if ( _fLockCount == 0 )
  3607.     {
  3608.         _fDestDraft = kODNULL;
  3609.         _fDestFrame = kODNULL;
  3610.         
  3611.         ODDeleteObject(_fClonedSUIDs);
  3612.         ODDeleteObject(_fLinksToCloneSUIDs);
  3613.     }
  3614.  
  3615.     ODDeleteObject(_fWeakClonedSUIDs);
  3616.     _fWeakClonedSUIDs = _fSavedWeakClonedSUIDs;
  3617.  
  3618.     SOM_CATCH_ALL
  3619.     SOM_ENDTRY
  3620. }
  3621.  
  3622. //------------------------------------------------------------------------------
  3623. // CMDraft: SetOriginalID
  3624. //------------------------------------------------------------------------------
  3625.  
  3626. SOM_Scope void  SOMLINK CMDraftSetOriginalID(CMDraft *somSelf, Environment* ev,
  3627.         ODStorageUnitID destID,
  3628.         ODStorageUnitID originalID)
  3629. {
  3630.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3631.     CMDraftMethodDebug("CMDraft","SetOriginalID");
  3632.  
  3633.     SOM_TRY
  3634.     
  3635.     TempODStorageUnit destSU = _fDestDraft->AcquireStorageUnit(ev, destID);
  3636.     ODSetULongProp(ev, destSU, kODPropOriginalID, kODULong, originalID);
  3637.  
  3638.     SOM_CATCH_ALL
  3639.     SOM_ENDTRY
  3640. }
  3641.  
  3642. //------------------------------------------------------------------------------
  3643. // CMDraft: GetOriginalID
  3644. //------------------------------------------------------------------------------
  3645. // An original ID may not be present in the root storage unit of the draft,
  3646. // since this SU is often constructed in place rather than cloned.
  3647. // An null object ID is returned if the property is not present.
  3648.  
  3649. SOM_Scope ODStorageUnitID  SOMLINK CMDraftGetOriginalID(CMDraft *somSelf, Environment* ev,
  3650.         ODStorageUnitID fromID)
  3651. {
  3652.     //CMDraftData *somThis = CMDraftGetData(somSelf);
  3653.     CMDraftMethodDebug("CMDraft","GetOriginalID");
  3654.     
  3655.     SOM_TRY
  3656.  
  3657.     TempODStorageUnit fromSU = somSelf->AcquireStorageUnit(ev, fromID);
  3658.     return (ODStorageUnitID)ODGetULongProp(ev, fromSU, kODPropOriginalID, kODULong);
  3659.  
  3660.     SOM_CATCH_ALL
  3661.     SOM_ENDTRY
  3662.     return 0;
  3663. }
  3664.  
  3665. //------------------------------------------------------------------------------
  3666. // CheckPartAction
  3667. //------------------------------------------------------------------------------
  3668.  
  3669. static ODBoolean CheckPartAction(void* k, void* v, ODULong s, void* r)
  3670. {
  3671.     ODID            originalID =  * (ODID *) k;
  3672.     ODID            interupdateID = * (ODID *) v;
  3673.     OpenHashTable*    targetParts = (OpenHashTable*) r;
  3674.     ODBoolean        result = kODFalse;
  3675.     Environment*     ev = somGetGlobalEnvironment();
  3676.  
  3677.     // Note that storage units in the original document draft may not be up to date
  3678.     // if changes have not been externalized.  In particular, a frame's storage
  3679.     // unit may not have a valid reference to its part's storage unit.  For this
  3680.     // reason, use the storage units in the data interchange draft instead.
  3681.  
  3682.     PRINT_CLONE("interupdateID %d, originalID %d\n", interupdateID, originalID);
  3683.  
  3684.     TempODStorageUnit interchangeSU = ::sInterchangeDraft->AcquireStorageUnit(ev, interupdateID);
  3685.     if ( ODSUExistsThenFocus(ev, interchangeSU, kODPropStorageUnitType, kODISOStr) )
  3686.     {
  3687.         if ( interchangeSU->GetSize(ev) == ODISOStrLength(kODFrameObject)+1 )
  3688.         {
  3689.             ODULong size = ODISOStrLength(kODFrameObject)+1;
  3690.             // Only read the same number of characters as in kODFrameObject, to prevent overwriting the
  3691.             // terminating zero byte of the buffer.
  3692.             if (ODGetISOStrProp(ev, interchangeSU, kODPropStorageUnitType, kODISOStr, (ODISOStr) ::sSUTypeBuffer, &size) 
  3693.                 != kODNULL)
  3694.             {
  3695.                 if (ODISOStrEqual(kODFrameObject, ::sSUTypeBuffer))
  3696.                 {
  3697.                     ODID interchangePartID = ODGetStrongSURefProp(ev, interchangeSU, kODPropPart, kODStrongStorageUnitRef);
  3698.                     if ( interchangePartID == kODNULLID )
  3699.                     {
  3700.                         // Note: If the reference isn't valid, ODGetStrongSURefProp will return
  3701.                         //   kODNULLID so it isn't necessary to call IsValidID instead.
  3702.                         PRINT_CLONE("Invalid part reference from frame id %d\n", interupdateID);
  3703.                         result = kODTrue;    // Better safe than sorry!
  3704.                     }
  3705.                     else if ( interchangePartID != ::sRootPartIDToIgnore )
  3706.                     {
  3707.                         ODID targetPartID = ::sInterchangeDraft->GetOriginalID(ev, interchangePartID);
  3708.                         PRINT_CLONE("Checking part id %d from frame id %d\n", targetPartID, originalID);
  3709.                         result = targetParts->Exists(&targetPartID);
  3710.                     }
  3711.                     else
  3712.                     {
  3713.                         PRINT_CLONE("Skipping root part id %d because it was not cloned\n", interchangePartID);
  3714.                     }
  3715.                 }
  3716.             }
  3717.         }
  3718.     }
  3719.  
  3720.     return result;
  3721. }
  3722.  
  3723. //------------------------------------------------------------------------------
  3724. // CMDraft: ContainingPartInClone
  3725. //------------------------------------------------------------------------------
  3726.  
  3727. SOM_Scope ODBoolean  SOMLINK CMDraftContainingPartInClone(CMDraft *somSelf, Environment* ev,
  3728.         ODFrame* targetFrame)
  3729. {
  3730.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3731.     CMDraftMethodDebug("CMDraft","ContainingPartInClone");
  3732.  
  3733.     ODBoolean        result = kODFalse;
  3734.     ODFrame*        frame;
  3735.     ODFrame*        nextFrame;
  3736.     ODID            partID;
  3737.  
  3738.     OpenHashTable* targetParts = kODNULL;
  3739.     OpenHashTable* clonedSUIDs = kODNULL;
  3740.  
  3741.     SOM_TRY
  3742.  
  3743.         ODMemoryHeapID    heap = somSelf->GetHeap(ev);
  3744.  
  3745.         PRINT_CLONE("ContainingPartInClone called with target frame id %d <%x>\n", targetFrame->GetID(ev), targetFrame);
  3746.  
  3747.         OpenHashTable* targetParts = new(heap) OpenHashTable(OpenHashTable::StdEqual,
  3748.                                                               OpenHashTable::StdHash,
  3749.                                                               heap);
  3750.         targetParts->Initialize(kInitialHashTableEntries, sizeof(ODID), 0, kODTrue);
  3751.     
  3752.         // Build a table of parts that own or embed the target frame
  3753.         frame = targetFrame;
  3754.         if ( frame )
  3755.             frame->Acquire(ev);
  3756.         while ( frame != kODNULL )
  3757.         {
  3758.             TempODFrame tempFrame = frame; // ensure it's released
  3759.             ODPart* part = frame->AcquirePart(ev);
  3760.             partID = part->GetID(ev);
  3761.             part->Release(ev);
  3762.             PRINT_CLONE("Adding target part id %d from frame id %d\n", partID, frame->GetID(ev));
  3763.             targetParts->ReplaceEntry(&partID, kODNULL);
  3764.     
  3765.             nextFrame = frame->AcquireContainingFrame(ev);
  3766.             if ( nextFrame == kODNULL )
  3767.             {
  3768.                 { TempODWindow window = frame->AcquireWindow(ev);
  3769.                   nextFrame = window->AcquireSourceFrame(ev);
  3770.                 }
  3771.  
  3772.                 // The source frame always displays the same part, so skip to its containing frame.
  3773.                 // Note that it must have a containing frame.
  3774.                 if ( nextFrame != kODNULL )
  3775.                 {
  3776.                     TempODFrame sourceFrame = nextFrame;
  3777.                     nextFrame = sourceFrame->AcquireContainingFrame(ev);
  3778.                 }
  3779.             }
  3780.             frame = nextFrame;
  3781.         }
  3782.     
  3783.         clonedSUIDs = new(heap) OpenHashTable(OpenHashTable::StdEqual,
  3784.                                                  OpenHashTable::StdHash,
  3785.                                                  heap);
  3786.  
  3787.         clonedSUIDs->Initialize(kInitialHashTableEntries,
  3788.                                   sizeof(ODStorageUnitID),
  3789.                                   sizeof(ODStorageUnitID));
  3790.     
  3791.         // Get the table of objects cloned into the data interchange draft
  3792.         ReadClonedObjectTable(ev, clonedSUIDs, somSelf);
  3793.                 
  3794.         // See if any frame of any target part is part of the clone
  3795.         ::sInterchangeDraft = somSelf;
  3796.         ::sSUTypeBuffer = (ODISOStr) ODNewPtrClear(ODISOStrLength(kODFrameObject) + 1);
  3797.         ::sRootPartIDToIgnore = ( _fRootPartReused ? kODNULLID : RootPartID(ev, somSelf) );
  3798.         result = clonedSUIDs->Walk(CheckPartAction, targetParts);
  3799.         ODDisposePtr(::sSUTypeBuffer);
  3800.     
  3801.     SOM_CATCH_ALL
  3802.     
  3803.     SOM_ENDTRY
  3804.  
  3805.     ODDeleteObject(targetParts);
  3806.     ODDeleteObject(clonedSUIDs);
  3807.     
  3808.     PRINT_CLONE("ContainingPartInClone returns %d\n", result);
  3809.  
  3810.     return result;
  3811. }
  3812.  
  3813. //------------------------------------------------------------------------------
  3814. // CompanionObjectID
  3815. //------------------------------------------------------------------------------
  3816.  
  3817. SOM_Scope ODID  SOMLINK CMDraftCompanionObjectID(CMDraft *somSelf, Environment *ev,
  3818.     ODID objectID)
  3819. {
  3820.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3821.     CMDraftMethodDebug("CMDraft","CompanionObjectID");
  3822.  
  3823.     ODStorageUnitID companionID = kODNULLID;
  3824.     ODPropertyName companionProperty = kODNULL;
  3825.  
  3826.     SOM_TRY
  3827.  
  3828.         if ( IsLinkObject(ev, somSelf, objectID) )
  3829.             companionProperty = kODPropLinkSource;
  3830.         else if ( IsLinkSourceObject(ev, somSelf, objectID) )
  3831.             companionProperty = kODPropLink;
  3832.     
  3833.         if ( companionProperty != kODNULL )
  3834.         {
  3835.             TempODStorageUnit objectSU = somSelf->AcquireStorageUnit(ev, objectID);
  3836.             if ( objectSU != kODNULL )
  3837.             {
  3838.                 companionID = ODGetWeakSURefProp(ev, objectSU, companionProperty, kODWeakStorageUnitRef);
  3839.             }
  3840.         }
  3841.  
  3842.     SOM_CATCH_ALL
  3843.  
  3844.     SOM_ENDTRY
  3845.  
  3846.     return companionID;
  3847. }
  3848.  
  3849. //------------------------------------------------------------------------------
  3850. //  CMDraft: CloneCompanionObject
  3851. //------------------------------------------------------------------------------
  3852. // If fromID is a link or link source object, clone its companion.
  3853. // Note that kODNULLID is always used as the scopeID, since scope is irrelevant
  3854. // for link and link source objects.
  3855.  
  3856. SOM_Scope ODID  SOMLINK CMDraftCloneCompanionObject(CMDraft *somSelf, Environment *ev,
  3857.         ODDraftKey key,
  3858.         ODID fromID)
  3859. {
  3860.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3861.     CMDraftMethodDebug("CMDraft","CloneCompanionObject");
  3862.  
  3863.     ODID toID = kODNULLID;    ODVolatile(toID);
  3864.  
  3865.     SOM_TRY
  3866.  
  3867.         ODStorageUnitID companionID = somSelf->CompanionObjectID(ev, fromID);
  3868.         if ( companionID != kODNULLID )
  3869.         {
  3870.             // Optimization: If the companion object has already been cloned,
  3871.             // there is no need to clone it again since scope is irrelevant for
  3872.             // these objects. [cc 9/28/95]
  3873.             _fClonedSUIDs->GetValue(&companionID, &toID);
  3874.             if ( toID == kODNULLID ) 
  3875.                 toID = somSelf->StrongClone(ev, key, companionID, kODNULLID, kODNULLID);
  3876.         }
  3877.  
  3878.     SOM_CATCH_ALL
  3879.     
  3880.     SOM_ENDTRY
  3881.  
  3882.     return toID;
  3883. }
  3884.  
  3885. //------------------------------------------------------------------------------
  3886. //  CMDraft: CompanionWasCloned
  3887. //------------------------------------------------------------------------------
  3888.  
  3889. SOM_Scope ODBoolean  SOMLINK CMDraftCompanionWasCloned(CMDraft *somSelf, Environment* ev,
  3890.         ODStorageUnitID fromID)
  3891. {
  3892.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3893.     CMDraftMethodDebug("CMDraft","CompanionWasCloned");
  3894.  
  3895.     ODBoolean result = kODFalse;
  3896.     
  3897.     SOM_TRY
  3898.         result = (somSelf->CompanionObjectID(ev, fromID) != kODNULLID);
  3899.     SOM_CATCH_ALL
  3900.     SOM_ENDTRY
  3901.  
  3902.     return result;
  3903. }
  3904.  
  3905. //------------------------------------------------------------------------------
  3906. //  CMDraft: GetCloneKind
  3907. //------------------------------------------------------------------------------
  3908.  
  3909. SOM_Scope ODCloneKind  SOMLINK CMDraftGetCloneKind(CMDraft *somSelf, Environment* ev)
  3910. {
  3911.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3912.     CMDraftMethodDebug("CMDraft","GetCloneKind");
  3913.     
  3914.     ODCloneKind cloneKind = _fCloneKind;
  3915.  
  3916.     SOM_TRY
  3917.  
  3918.     if ( cloneKind == kODClonePaste )
  3919.     {
  3920.         if ( (GetOriginalCloneKind(ev, somSelf) == kODCloneCut) && (GetOriginalDraft(ev, somSelf) == _fDestDraft) )
  3921.             cloneKind = kODCloneDropMove;
  3922.         else
  3923.             cloneKind = kODCloneDropCopy;
  3924.     }
  3925.     else if ( cloneKind == kODCloneToFile )
  3926.     {
  3927.         cloneKind = kODCloneDropCopy;
  3928.     }
  3929.     
  3930.     SOM_CATCH_ALL
  3931.     SOM_ENDTRY
  3932.     return cloneKind;
  3933. }
  3934.  
  3935. //------------------------------------------------------------------------------
  3936. //  CMDraft: DeferStrongClone
  3937. //------------------------------------------------------------------------------
  3938. //
  3939. // Defers cloning of a link or link source object in this draft to the 
  3940. // destination draft.  As in a weak clone, a storage unit is created in the
  3941. // destination draft an its ID is returned.  In addition, the object is put
  3942. // in a list of link objects.  EndClone should iterate over the list and
  3943. // clone those objects once the fate of their companion objects is known.
  3944.  
  3945. SOM_Scope ODID  SOMLINK CMDraftDeferStrongClone(CMDraft *somSelf, Environment* ev,
  3946.         ODID fromID)
  3947. {
  3948.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3949.     CMDraftMethodDebug("CMDraft","DeferStrongClone");
  3950.  
  3951.     ODID toID = kODNULLID; ODVolatile(toID);
  3952.  
  3953.     SOM_TRY
  3954.  
  3955.         ASSERT(IsEitherLinkObject(ev, somSelf, fromID), kODErrInvalidID);
  3956.  
  3957.         ASSERT(_fLinksToCloneSUIDs != kODNULL, kODErrCannotDeferClone);
  3958.  
  3959.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  3960.         if ( toID == kODNULLID )
  3961.         {
  3962.             TempODStorageUnit toSU = _fDestDraft->CreateStorageUnit(ev);
  3963.             toID = toSU->GetID(ev);
  3964.             _fWeakClonedSUIDs->ReplaceEntry(&fromID, &toID);
  3965.             PRINT_CLONE("Putting deferred clone from ID %d to ID %d on weak clone list\n", fromID, toID);
  3966.         }
  3967.  
  3968.         ODID toCloneID = kODNULLID;
  3969.         _fLinksToCloneSUIDs->GetValue(&fromID, &toCloneID);
  3970.         if ( toCloneID == kODNULLID )
  3971.         {
  3972.             _fLinksToCloneSUIDs->ReplaceEntry(&fromID, &toID);
  3973.             PRINT_CLONE("Deferring clone from ID %d to ID %d\n", fromID, toID);
  3974.         }
  3975.  
  3976.     SOM_CATCH_ALL
  3977.  
  3978.     SOM_ENDTRY
  3979.  
  3980.     return toID;
  3981. }
  3982.  
  3983. //------------------------------------------------------------------------------
  3984. //  CMDraft: DoDeferredClones
  3985. //------------------------------------------------------------------------------
  3986.  
  3987. SOM_Scope void  SOMLINK CMDraftDoDeferredClones(CMDraft *somSelf, Environment* ev,
  3988.     ODDraftKey    key)
  3989. {
  3990.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3991.     CMDraftMethodDebug("CMDraft","DoDeferredClones");
  3992.  
  3993.     ODStorageUnitID fromID;
  3994.     ODStorageUnitID toID;
  3995.     ODStorageUnitID companionID;
  3996.     ODStorageUnitID toCompanionID;
  3997.  
  3998.     if ( _fLinksToCloneSUIDs != kODNULL )
  3999.     {
  4000.         SOM_TRY
  4001.  
  4002.             PRINT_CLONE("Cloning deferred link and link source objects\n");
  4003.  
  4004.             OpenHashTableIterator iter(_fLinksToCloneSUIDs);
  4005.             for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID))
  4006.             {
  4007.                 companionID = somSelf->CompanionObjectID(ev, fromID);
  4008.                 if ( companionID != kODNULLID )
  4009.                 {
  4010.                     // Because cloning both link and link source objects is deferred,
  4011.                     // it suffices to check just _fLinksToCloneSUIDs to see if the
  4012.                     // companion has also been deferred.
  4013.                     toCompanionID = kODNULLID;    // GetValue doesn't change if not found
  4014.                     _fLinksToCloneSUIDs->GetValue(&companionID, &toCompanionID);
  4015.                     if ( toCompanionID != kODNULLID )
  4016.                     {
  4017.                         // Previously, we just created a storage unit for the object,
  4018.                         // so now we must clone into that storage unit
  4019.                         somSelf->StrongClone(ev, key, fromID, toID, kODNULLID);
  4020.                     }
  4021.                     else
  4022.                     {
  4023.                         // The empty storage unit created in the destination draft
  4024.                         // will be removed with others that were only weakly cloned
  4025.                         PRINT_CLONE("Companion object ID %d of ID %d was not cloned\n", companionID, fromID);
  4026.                     }
  4027.                 }
  4028.                 else
  4029.                 {
  4030.                     PRINT_CLONE("No companion for object ID %d\n", fromID);
  4031.                 }
  4032.             }
  4033.  
  4034.         SOM_CATCH_ALL
  4035.         
  4036.         SOM_ENDTRY
  4037.     }
  4038. }
  4039.  
  4040. //------------------------------------------------------------------------------
  4041. //  CMDraft: DropCopyClone
  4042. //------------------------------------------------------------------------------
  4043. //
  4044. // Implements strong cloning of objects during a paste or drop of copied content.
  4045. // Takes into consideration whether the source draft is an
  4046. // intermediate draft or a document draft (for example, an OpenDoc file dragged
  4047. // in from the Finder).  If the clone is from an intermediat draft back into
  4048. // the same document draft, the original object ID may be substituted, or a null
  4049. // object ID may be returned.  Enforces rules for copying link source and link
  4050. // objects.
  4051.  
  4052. SOM_Scope ODID  SOMLINK CMDraftDropCopyClone(CMDraft *somSelf, Environment* ev,
  4053.         ODDraftKey    key,
  4054.         ODID        fromID,
  4055.         ODID        toID,
  4056.         ODID        scopeID)
  4057. {
  4058.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4059.     CMDraftMethodDebug("CMDraft","DropCopyClone");
  4060.  
  4061.     ODID clonedID = kODNULLID; ODVolatile(clonedID);
  4062.  
  4063.     SOM_TRY
  4064.  
  4065.         ASSERT(somSelf->GetCloneKind(ev) == kODCloneDropCopy, kODErrInvalidCloneKind);
  4066.     
  4067.         if ( IsLinkObject(ev, somSelf, fromID) )
  4068.         {
  4069.             ODDraft* originalDraft = GetOriginalDraft(ev, somSelf);
  4070.             if ( originalDraft == _fDestDraft )
  4071.             {
  4072.                 // Clone is from an intermediate draft back into the original draft.
  4073.                 // Because the clone is from an intermediate draft, we can check
  4074.                 // to see if the link source object was also cloned into the
  4075.                 // intermediate draft.
  4076.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4077.                 {
  4078.                     // The link source object was copied, so clone the link object
  4079.                     // to create a new one.
  4080.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4081.                 }
  4082.                 else
  4083.                 {
  4084.                     // The link source object was not cloned, so substitute the ID
  4085.                     // of the original link object so copied destinations reference
  4086.                     // the original link object.
  4087.                     ASSERT(toID == 0, kODErrInvalidID);
  4088.                     clonedID = somSelf->GetOriginalID(ev, fromID);
  4089.                     ASSERT(_fDestDraft->IsValidID(ev, clonedID), kODErrInvalidID);
  4090.                     PRINT_CLONE("Reusing existing link object id = %d for cloned object %d\n", clonedID, fromID);
  4091.                 }
  4092.             }
  4093.             else if ( originalDraft != kODNULL )
  4094.             {
  4095.                 // Clone is cross-draft via an intermediate draft.  Only link
  4096.                 // and link source pairs are copied.
  4097.                 // Because the clone is from an intermediate draft, we can check
  4098.                 // to see if the link source object was also cloned into the
  4099.                 // intermediate draft.
  4100.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4101.                 {
  4102.                     // The link source object was copied, so clone the link object
  4103.                     // to create a new one.
  4104.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4105.                 }
  4106.                 else
  4107.                 {
  4108.                     // The link source object was not cloned, so don't clone the link
  4109.                     clonedID = kODNULLID;
  4110.                     PRINT_CLONE("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  4111.                 }
  4112.             }
  4113.             else
  4114.             {
  4115.                 // Clone is from a document draft.  Create a storage unit and return
  4116.                 // its ID.  EndClone will either clone the object or remove the
  4117.                 // storage unit from the destination draft.
  4118.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  4119.             }
  4120.         }
  4121.         else if ( IsLinkSourceObject(ev, somSelf, fromID) )
  4122.         {
  4123.             if ( GetOriginalDraft(ev, somSelf) != kODNULL )
  4124.             {
  4125.                 // Clone is from an intermediate draft (it doesn't matter if the
  4126.                 // destination draft is the same as the original draft or not).
  4127.                 // Because the clone is from an intermediate draft, we can check
  4128.                 // to see if the link object was also cloned into the
  4129.                 // intermediate draft.
  4130.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4131.                 {
  4132.                     // The link object was copied, so clone the link source object
  4133.                     // to create a new one.
  4134.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4135.                 }
  4136.                 else
  4137.                 {
  4138.                     // The link object was not cloned, so don't clone the link source
  4139.                     clonedID = kODNULLID;
  4140.                     PRINT_CLONE("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  4141.                 }
  4142.             }
  4143.             else
  4144.             {
  4145.                 // Clone is from a document draft.  Create a storage unit and return
  4146.                 // its ID.  EndClone will either clone the object or remove the
  4147.                 // storage unit from the destination draft.
  4148.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  4149.             }
  4150.         }
  4151.         else
  4152.         {
  4153.             // Not a link or link source object, so clone it
  4154.             clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4155.         }
  4156.     
  4157.     SOM_CATCH_ALL
  4158.     
  4159.     SOM_ENDTRY
  4160.  
  4161.     return clonedID;
  4162. }
  4163.  
  4164. //------------------------------------------------------------------------------
  4165. //  CMDraft: DropMoveClone
  4166. //------------------------------------------------------------------------------
  4167. //
  4168. // Implements strong cloning of objects during a paste of cut content or a drop
  4169. // of moved content.  Takes into consideration whether the source draft is an
  4170. // intermediate draft or a document draft (for example, an OpenDoc file dragged
  4171. // in from the Finder).  If the clone is from an intermediate draft back into
  4172. // the same document draft, the original object ID may be substituted, or a null
  4173. // object ID may be returned.  Enforces rules for moving link source and link
  4174. // objects. When moved to another draft, links behave as if copied. [cc]
  4175.  
  4176. SOM_Scope ODID  SOMLINK CMDraftDropMoveClone(CMDraft *somSelf, Environment* ev,
  4177.         ODDraftKey    key,
  4178.         ODID        fromID,
  4179.         ODID        toID,
  4180.         ODID        scopeID)
  4181. {
  4182.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4183.     CMDraftMethodDebug("CMDraft","DropMoveClone");
  4184.  
  4185.     ODID clonedID = kODNULLID; ODVolatile(clonedID);
  4186.  
  4187.     SOM_TRY
  4188.  
  4189.         ASSERT(somSelf->GetCloneKind(ev) == kODCloneDropMove, kODErrInvalidCloneKind);
  4190.     
  4191.         ODDraft* originalDraft = GetOriginalDraft(ev, somSelf);
  4192.         if ( originalDraft == _fDestDraft )
  4193.         {
  4194.             // Clone is from an intermediate draft back into the original draft.
  4195.             // In this case, no distinction is made between link, link source,
  4196.             // and other objects being cloned.
  4197.             // toID will be non-zero if the object has already been weakly cloned.
  4198.             // If the original object is still present in the destination draft,
  4199.             // use it unless the caller explicitly cloned into another storage unit. [cc]
  4200.  
  4201. #ifdef DebugClone
  4202.             TempODISOStr suType = GetStorageUnitType(ev, somSelf, fromID);
  4203.             PRINT_CLONE("DropMoveClone: Type of from ID %d is %s\n", fromID, (ODISOStr) suType);
  4204. #endif
  4205.  
  4206.             ODID originalID = somSelf->GetOriginalID(ev, fromID);
  4207.             if ( _fDestDraft->IsValidID(ev, originalID) )
  4208.             {
  4209.                 if ( toID == 0 )
  4210.                 {
  4211.                     if ( IsFrameObject(ev, somSelf, fromID) )
  4212.                     {
  4213.                         clonedID = somSelf->CloneMovedFrame(ev, fromID);
  4214.                         PRINT_CLONE("CMDraftStrongClone from frame ID %d to new frame ID %d\n", fromID, clonedID);
  4215.                     }
  4216.                     else
  4217.                     {
  4218.                         clonedID = originalID;
  4219.                         PRINT_CLONE("CMDraftStrongClone from ID %d to substitute ID %d\n", fromID, clonedID);
  4220.                     }
  4221.                 }
  4222.                 else if ( toID == originalID )
  4223.                 {
  4224.                     // I don't know why a part would ask to clone back into the
  4225.                     // original object!  The safest thing is to just return the 
  4226.                     // original object. [cc 8/16/96]
  4227.                     clonedID = originalID;
  4228.                     PRINT_CLONE("CMDraftStrongClone from ID %d to substitute ID %d\n", fromID, clonedID);
  4229.                 }
  4230.                 else
  4231.                 {
  4232.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4233.                 }
  4234.             }
  4235.             else
  4236.             {
  4237.                 if ( originalID != kODNULLID )
  4238.                     PRINT_CLONE("Original id = %d of from id %d is not valid\n", originalID, fromID);
  4239.                 clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4240.             }
  4241.             somSelf->CheckClonedObject(ev, fromID, clonedID, originalID);
  4242.         }
  4243.         else if ( IsEitherLinkObject(ev, somSelf, fromID) )
  4244.         {
  4245.             if ( originalDraft != kODNULL )
  4246.             {
  4247.                 // Clone is cross-draft via an intermediate draft.  Only link
  4248.                 // and link source pairs are copied.
  4249.                 // Because the clone is from an intermediate draft, we can check
  4250.                 // to see if the companion object was also cloned into the
  4251.                 // intermediate draft.
  4252.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4253.                 {
  4254.                     // The link source object was copied, so clone the link object
  4255.                     // to create a new one.
  4256.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4257.                 }
  4258.                 else
  4259.                 {
  4260.                     // The companion object was not cloned, so don't clone the link
  4261.                     clonedID = kODNULLID;
  4262.                     PRINT_CLONE("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  4263.                 }
  4264.             }
  4265.             else
  4266.             {
  4267.                 // Clone is from a document draft.  Create a storage unit and return
  4268.                 // its ID.  EndClone will either clone the object or remove the
  4269.                 // storage unit from the destination draft.
  4270.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  4271.             }
  4272.         }
  4273.         else
  4274.         {
  4275.             // Other objects moved across drafts are always cloned
  4276.             clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4277.         }
  4278.     
  4279.     SOM_CATCH_ALL
  4280.     
  4281.     SOM_ENDTRY
  4282.  
  4283.     return clonedID;
  4284. }
  4285.  
  4286. //------------------------------------------------------------------------------
  4287. //  CMDraft: DoWeakClone
  4288. //------------------------------------------------------------------------------
  4289. //
  4290. // Implements weak clone of objects that have not already been strongly or
  4291. // weakly cloned.
  4292. // If link objects are copied or moved across a draft...
  4293.  
  4294. SOM_Scope ODID  SOMLINK CMDraftDoWeakClone(CMDraft *somSelf, Environment* ev,
  4295.         ODID fromID)
  4296. {
  4297.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4298.     CMDraftMethodDebug("CMDraft","DoWeakClone");
  4299.  
  4300.     ODID        clonedID = kODNULLID; ODVolatile(clonedID);
  4301.     ODBoolean    doWeakClone = kODFalse;
  4302.     ODDraft*    originalDraft = kODNULL;
  4303.  
  4304.     SOM_TRY
  4305.  
  4306.         ODCloneKind cloneKind = somSelf->GetCloneKind(ev);
  4307.         
  4308.         if ( cloneKind == kODCloneDropCopy )
  4309.         {
  4310.             if ( IsLinkObject(ev, somSelf, fromID) )
  4311.             {
  4312.                 originalDraft = GetOriginalDraft(ev, somSelf);
  4313.                 if ( originalDraft == _fDestDraft )
  4314.                 {
  4315.                     // Clone is from an intermediate draft back into the original draft.
  4316.                     // Because the clone is from an intermediate draft, we can check
  4317.                     // to see if the link source object was also cloned into the
  4318.                     // intermediate draft.
  4319.                     if ( somSelf->CompanionWasCloned(ev, fromID) )
  4320.                     {
  4321.                         // The link source object was copied, so clone the link object
  4322.                         // to create a new one.
  4323.                         doWeakClone = kODTrue;
  4324.                     }
  4325.                     else
  4326.                     {
  4327.                         // The link source object was not cloned, so substitute the ID
  4328.                         // of the original link object so copied destinations reference
  4329.                         // the original link object.
  4330.                         clonedID = somSelf->GetOriginalID(ev, fromID);
  4331.                         ASSERT(_fDestDraft->IsValidID(ev, clonedID), kODErrInvalidID);
  4332.                         PRINT_CLONE("Reusing existing link object id = %d for weakly cloned object %d\n", clonedID, fromID);
  4333.                     }
  4334.                 }
  4335.                 else if ( originalDraft != kODNULL )
  4336.                 {
  4337.                     // Clone is cross-draft via an intermediate draft.  Only link
  4338.                     // and link source pairs are copied.
  4339.                     // Because the clone is from an intermediate draft, we can check
  4340.                     // to see if the link source object was also cloned into the
  4341.                     // intermediate draft.  If the link source was cloned, we can
  4342.                     // weakly clone this link object.
  4343.  
  4344.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4345.                 }
  4346.                 else
  4347.                 {
  4348.                     // Clone is from a document draft.  Weakly clone it.
  4349.                     doWeakClone = kODTrue;
  4350.                 }
  4351.             }
  4352.             else if ( IsLinkSourceObject(ev, somSelf, fromID) )
  4353.             {
  4354.                 originalDraft = GetOriginalDraft(ev, somSelf);
  4355.                 if ( originalDraft != kODNULL )
  4356.                 {
  4357.                     // Clone is from an intermediate draft.
  4358.                     // Because the clone is from an intermediate draft, we can check
  4359.                     // to see if the link object was also cloned into the
  4360.                     // intermediate draft.
  4361.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4362.                 }
  4363.                 else
  4364.                 {
  4365.                     // Clone is from a document draft.  Weakly clone it.
  4366.                     doWeakClone = kODTrue;
  4367.                 }
  4368.             }
  4369.             else
  4370.             {
  4371.                 // Weakly clone all other objects
  4372.                 doWeakClone = kODTrue;
  4373.             }
  4374.         }
  4375.         else if ( cloneKind == kODCloneDropMove )
  4376.         {
  4377.             originalDraft = GetOriginalDraft(ev, somSelf);
  4378.             if ( originalDraft == _fDestDraft )
  4379.             {
  4380.                 // Clone is from an intermediate draft back into the original draft.
  4381.                 // In this case, no distinction is made between link, link source,
  4382.                 // and other objects being cloned.
  4383.                 ODID originalID = somSelf->GetOriginalID(ev, fromID);
  4384.                 if ( _fDestDraft->IsValidID(ev, originalID) )
  4385.                 {
  4386.                     clonedID = originalID;
  4387.                     
  4388.                     // Assumption: If the original object is substituted for a
  4389.                     // weakly-referenced clone, the clone is also strongly-referenced
  4390.                     // and will be strongly cloned back into the draft, so its
  4391.                     // unnecessary to call somSelf->CheckClonedObject here.
  4392.                 }
  4393.                 else
  4394.                 {
  4395.                     doWeakClone = kODTrue;
  4396.                     if ( originalID != kODNULLID )
  4397.                         PRINT_CLONE("Original id = %d is not valid\n", originalID);
  4398.                 }
  4399.             }
  4400.             else if ( IsEitherLinkObject(ev, somSelf, fromID) )
  4401.             {
  4402.                 if ( originalDraft != kODNULL )
  4403.                 {
  4404.                     // Clone is cross-draft via an intermediate draft.  Only link
  4405.                     // and link source pairs are copied.
  4406.                     // Because the clone is from an intermediate draft, we can check
  4407.                     // to see if the link source object was also cloned into the
  4408.                     // intermediate draft.
  4409.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4410.                 }
  4411.                 else
  4412.                 {
  4413.                     // Clone is from a document draft.
  4414.                     doWeakClone = kODTrue;
  4415.                 }
  4416.             }
  4417.             else
  4418.             {
  4419.                 // Other objects moved across drafts are always cloned
  4420.                 doWeakClone = kODTrue;
  4421.             }
  4422.         }
  4423.         else
  4424.         {
  4425.             // Note a paste or a drop; do a weak clone
  4426.             doWeakClone = kODTrue;
  4427.         }
  4428.  
  4429.         if ( doWeakClone )
  4430.         {
  4431.             TempODStorageUnit toSU = _fDestDraft->CreateStorageUnit(ev);
  4432.             clonedID = toSU->GetID(ev);
  4433.             _fWeakClonedSUIDs->ReplaceEntry(&fromID, &clonedID);
  4434.         }
  4435.  
  4436. #ifdef DebugClone
  4437.         if ( doWeakClone )
  4438.             somPrintf("CMDraftWeakClone from ID %d to ID %d", fromID, clonedID);
  4439.         else
  4440.             somPrintf("CMDraftWeakClone from ID %d to substitute ID %d", fromID, clonedID);
  4441.         TempODISOStr suType = GetStorageUnitType(ev, somSelf, fromID);
  4442.         somPrintf(" type %s\n", (ODISOStr) suType);
  4443. #endif
  4444.  
  4445.     SOM_CATCH_ALL
  4446.     
  4447.     SOM_ENDTRY
  4448.  
  4449.     return clonedID;
  4450. }
  4451.  
  4452. //------------------------------------------------------------------------------
  4453. // CMDraft: Clone
  4454. //------------------------------------------------------------------------------
  4455. //
  4456. // It should really be replaced by a table-driven algorithm.  There are only 
  4457. // three possible actions when cloning a link or link source object:
  4458. //        (1) Go ahead and clone the link,
  4459. //        (2) Don't clone the link,
  4460. //        (3) Substitute the original link rather than clone in a duplicate
  4461. // However, there are four factors that determine which action should be taken.
  4462. // There are 8x3x2x2 = 96 distinct combinations of these factors; however,
  4463. // most combinations are impossible or illegal.
  4464. // The switch statement is an embodyment in code of the resulting sparse matrix.
  4465. // Several cases are sometimes handled at once.  Only by going back to the full 
  4466. // case analysis represented by a table can one understand this code.
  4467. // 
  4468. // Note that its possible that a link object's companion doesn't exist; in this
  4469. // case the link is broken and won't be copied.
  4470. // 
  4471.  
  4472. SOM_Scope ODID  SOMLINK CMDraftClone(CMDraft *somSelf, Environment *ev,
  4473.         ODDraftKey key,
  4474.         ODID fromID,
  4475.         ODID toObjectID,
  4476.         ODID scopeID)
  4477. {
  4478.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4479.     CMDraftMethodDebug("CMDraft","Clone");
  4480.  
  4481.     SOM_TRY
  4482.  
  4483.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  4484.         THROW(kODErrInvalidDraftKey);
  4485.  
  4486.     ODStorageUnitID    toID = 0;
  4487.  
  4488.     switch ( somSelf->GetCloneKind(ev) )
  4489.     {
  4490.     case kODCloneAll:
  4491.         toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4492.         somSelf->CloneCompanionObject(ev, key, fromID);
  4493.         break;
  4494.  
  4495.     case kODCloneFromLink:
  4496.     case kODCloneToLink:
  4497.         if ( IsNeitherLinkObject(ev, somSelf, fromID) )
  4498.             toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4499.         break;
  4500.  
  4501.     case kODCloneCopy:
  4502.     case kODCloneCut:
  4503.         toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4504.         somSelf->SetOriginalID(ev, toID, fromID);
  4505.         break;
  4506.         
  4507.     case kODCloneDropCopy:
  4508.         toID = somSelf->DropCopyClone(ev, key, fromID, toObjectID, scopeID);
  4509.         break;
  4510.  
  4511.     case kODCloneDropMove:
  4512.         toID = somSelf->DropMoveClone(ev, key, fromID, toObjectID, scopeID);
  4513.         break;
  4514.  
  4515.     default:
  4516.         break;
  4517.     }
  4518.  
  4519.     return toID;
  4520.  
  4521.     SOM_CATCH_ALL
  4522.     SOM_ENDTRY
  4523.     return 0;
  4524. }
  4525.  
  4526. //------------------------------------------------------------------------------
  4527. // CMDraft: StrongClone
  4528. //------------------------------------------------------------------------------
  4529.  
  4530. SOM_Scope ODID  SOMLINK CMDraftStrongClone(CMDraft *somSelf, Environment *ev,
  4531.         ODDraftKey key,
  4532.         ODID fromID,
  4533.         ODID toObjectID,
  4534.         ODID scopeID)
  4535. {
  4536.     SOM_TRY
  4537.     
  4538.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4539.     CMDraftMethodDebug("CMDraft","StrongClone");
  4540.  
  4541.     PRINT_CLONE("CMDraftStrongClone from ID %d to ID %d scope ID %d\n", fromID, toObjectID, scopeID);
  4542.  
  4543.     ODStorageUnitID        toID = 0;
  4544.     TempODStorageUnit toSU = kODNULL;
  4545.     
  4546.     _fClonedSUIDs->GetValue(&fromID, &toID);
  4547.     if (toID == 0) {
  4548.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  4549.         if (toID == 0) {
  4550.             if (toObjectID != 0) 
  4551.                 toSU = _fDestDraft->AcquireStorageUnit(ev, toObjectID);
  4552.             else
  4553.                 toSU = _fDestDraft->CreateStorageUnit(ev);
  4554.             toID = toSU->GetID(ev);
  4555.             _fClonedSUIDs->ReplaceEntry(&fromID, &toID);
  4556.         }
  4557.         else {
  4558.             if ((toObjectID != 0) && (toObjectID != toID))
  4559.                 THROW(kODErrInvalidID);
  4560.             _fWeakClonedSUIDs->RemoveEntry(&fromID);
  4561.             _fClonedSUIDs->ReplaceEntry(&fromID, &toID);
  4562.             toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  4563.         }
  4564.     }
  4565.     else {
  4566.         if ((toObjectID != 0) && (toObjectID != toID))
  4567.             THROW(kODErrInvalidID);
  4568.         toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  4569.     }
  4570.         
  4571.     ODPersistentObject *fromObject = somSelf->RetrievePersistentObject(ev, fromID);
  4572.     if ( fromObject ) {
  4573.         TempODRefCntObject tempFromObject = fromObject; // so it gets released
  4574.         TempODFrame scopeFrame = kODNULL;
  4575.         if (scopeID != 0)
  4576.             scopeFrame = somSelf->AcquireFrame(ev, scopeID);
  4577.         fromObject->CloneInto(ev, key, toSU, scopeFrame);
  4578.         ODStorageUnit* fromSU = fromObject->GetStorageUnit(ev);
  4579.         if (fromSU != kODNULL)
  4580.             CopyDraftAnnotations(ev, fromSU, toSU);
  4581.     }
  4582.     else {
  4583.         TempODStorageUnit fromSU = somSelf->AcquireStorageUnit(ev, fromID);
  4584.         if (fromSU != kODNULL) {
  4585.             fromSU->CloneInto(ev, key, toSU, scopeID);
  4586.             ODBoolean keepProxyProperties = (_fCloneKind == kODCloneToFile)
  4587.                                         || (_fCloneKind == kODCloneAll);
  4588.             RemoveDataInterchangeProperties(ev, toSU, keepProxyProperties);
  4589. //            CopyDraftAnnotations(ev, fromSU, toSU);
  4590.         }
  4591.     }
  4592.  
  4593.     PRINT_CLONE("Done CMDraftStrongClone from ID %d to ID %d\n", fromID, toID);
  4594.  
  4595.     return toID;
  4596.  
  4597.     SOM_CATCH_ALL
  4598.     SOM_ENDTRY
  4599.     return 0;
  4600. }        
  4601.  
  4602. //------------------------------------------------------------------------------
  4603. // CMDraft: WeakClone
  4604. //------------------------------------------------------------------------------
  4605.  
  4606. SOM_Scope ODID  SOMLINK CMDraftWeakClone(CMDraft *somSelf, Environment *ev,
  4607.         ODDraftKey key,
  4608.         ODID fromID,
  4609.         ODID toObjectID,
  4610.         ODID scopeID)
  4611. {
  4612.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4613.     CMDraftMethodDebug("CMDraft","Clone");
  4614.  
  4615.     ODUnused(scopeID);
  4616.  
  4617.     SOM_TRY
  4618.  
  4619.     ODStorageUnitID    toID = 0;
  4620.     
  4621.     _fClonedSUIDs->GetValue(&fromID, &toID);
  4622.     if (toID == 0)
  4623.     {
  4624.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  4625.         if (toID == 0)
  4626.         {
  4627.             toID = toObjectID;
  4628.             if ( toID == 0 )
  4629.             {
  4630.                 // Note that this may substitute the null object id, which
  4631.                 // will be returned instead of a valid object id!
  4632.                 toID = somSelf->DoWeakClone(ev, fromID);
  4633.             }
  4634.         }
  4635.     }
  4636.     if ((toObjectID != 0) && (toObjectID != toID))
  4637.         THROW(kODErrInvalidID);
  4638.     
  4639.     return toID;
  4640.  
  4641.     SOM_CATCH_ALL
  4642.     SOM_ENDTRY
  4643.     return 0;
  4644. }
  4645.  
  4646. //------------------------------------------------------------------------------
  4647. // CMDraft: CloneMovedFrame
  4648. //------------------------------------------------------------------------------
  4649. //
  4650. // Implements cloning a frame from an intermediate draft back into the original
  4651. // draft.  This method should not be called when cloning across documents.
  4652.  
  4653. SOM_Scope ODID  SOMLINK CMDraftCloneMovedFrame(CMDraft *somSelf, Environment *ev,
  4654.         ODID fromID)
  4655. {
  4656.     TempODFrame frame(kODNULL); 
  4657.  
  4658.     SOM_TRY
  4659.     
  4660.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4661.     CMDraftMethodDebug("CMDraft","CloneMovedFrame");
  4662.  
  4663.     PRINT_CLONE("CMDraft::CloneMovedFrame from ID %d\n", fromID);
  4664.     
  4665.     ODStorageUnitID toID = kODNULLID;
  4666.     TempODStorageUnit toSU = kODNULL;
  4667.     
  4668.     _fClonedSUIDs->GetValue(&fromID, &toID);
  4669.     if ( toID != kODNULLID )
  4670.     {
  4671.         PRINT_CLONE("CMDraft::CloneMovedFrame: Already moved ID %d to ID %d\n", fromID, toID);
  4672.         return toID;
  4673.     }
  4674.  
  4675.     _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  4676.     if ( toID == kODNULLID )
  4677.     {
  4678.         ODID originalID = somSelf->GetOriginalID(ev, fromID);
  4679.         if ( _fDestDraft->IsValidID(ev, originalID) )
  4680.         {
  4681.             TempODFrame sourceFrame = _fDestDraft->AcquireFrame(ev, originalID);
  4682.             TempODPart displayedPart = sourceFrame->AcquirePart(ev);
  4683.             TempODShape frameShape = sourceFrame->AcquireFrameShape(ev, kODNULL);
  4684.             TempODShape newShape = frameShape->Copy(ev);
  4685.  
  4686.             // In the call to CreateFrame, the containing frame is specified to 
  4687.             // be the destination frame, even though this is not always correct 
  4688.             // (the destination part may create a new embedded frame in which to 
  4689.             // embed this frame).  A null destination frame is not used because 
  4690.             // this marks the frame as a root frame, and some parts use this to
  4691.             // determine whether to dispose the frame's window. [cc]
  4692.             frame = _fDestDraft->CreateFrame(ev, 
  4693.                 kODFrameObject,
  4694.                 _fDestFrame,            // A viable containing frame 
  4695.                 newShape,
  4696.                 (ODCanvas*) kODNULL,    // A null biasCanvas matches AcquireFrameShape
  4697.                 displayedPart,
  4698.                 sourceFrame->GetViewType(ev),
  4699.                 sourceFrame->GetPresentation(ev),
  4700.                 sourceFrame->IsSubframe(ev),
  4701.                 sourceFrame->IsOverlaid(ev));
  4702.             
  4703.             PRINT_CLONE("CMDraft::CloneMovedFrame: Created frame %x\n", (ODFrame*) frame);
  4704.  
  4705.             TRY
  4706.                 frame->SetIsMoving(ev, kODTrue);
  4707.                 displayedPart->AttachSourceFrame(ev, frame, sourceFrame);
  4708.                 frame->SetIsMoving(ev, kODFalse);
  4709.                 
  4710.                 // The embedding part expects the frame to have a null containing frame
  4711.                 frame->SetContainingFrame(ev, kODNULL);
  4712.             CATCH_ALL
  4713.                 frame->Remove(ev);        // Displayed part should remove embedded frames it created
  4714.                 frame.DontRelease();    // Remove decrements reference count
  4715.                 RERAISE;
  4716.             ENDTRY
  4717.  
  4718.             toID = frame->GetID(ev);
  4719.             _fClonedSUIDs->ReplaceEntry(&fromID, &toID);
  4720.  
  4721.             PRINT_CLONE("CMDraft::CloneMovedFrame from ID %d to ID %d\n", fromID, toID);
  4722.         }
  4723.         else
  4724.         {
  4725.             PRINT("CMDraft::CloneMovedFrame: Original ID %d of ID %d is not valid!\n", originalID, fromID);
  4726.             THROW(kODErrInvalidID);
  4727.         }
  4728.     }
  4729.     else
  4730.     {
  4731.         // If parts follow the recipe for dropping or pasting a moved frame,
  4732.         // I don't think they will ever weakly clone an embedded frame before strongly cloning it.
  4733.         // Because a storage unit was created in the destination draft when the frame
  4734.         // was weakly cloned, we cannot turn that storage unit into a frame using the
  4735.         // existing ODDraft API. [cc]
  4736.         WARN("CMDraft::CloneMovedFrame - frame ID %d already weakly cloned; can't proceed\n", fromID);
  4737.         toID = kODNULLID;
  4738.         THROW(kODErrCannotCloneFrame);
  4739.     }
  4740.  
  4741.     return toID;
  4742.  
  4743.     SOM_CATCH_ALL_ENDTRY
  4744.  
  4745.     return kODNULLID;
  4746. }
  4747.  
  4748. //------------------------------------------------------------------------------
  4749. // CMDraft: IsValidDraftKey
  4750. //------------------------------------------------------------------------------
  4751.  
  4752. SOM_Scope ODBoolean  SOMLINK CMDraftIsValidDraftKey(CMDraft *somSelf, Environment *ev,
  4753.         ODDraftKey key)
  4754. {
  4755.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4756.     CMDraftMethodDebug("CMDraft","IsValidDraftKey");
  4757.  
  4758.     return ((key != kODNULLKey) && (_fCurrentKey == key) ? kODTrue : kODFalse);
  4759. }
  4760.  
  4761. //------------------------------------------------------------------------------
  4762. // CopyProperty
  4763. //------------------------------------------------------------------------------
  4764.  
  4765. static void CopyProperty(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU, ODPropertyName prop)
  4766. {
  4767.     // Assuming fromSU is focused to prop.    
  4768.     // Copy all values into toSU, overwriting any existing values there.
  4769.  
  4770.     PreserveFocus fromFocus(ev, fromSU);
  4771.     PreserveFocus toFocus(ev, toSU);
  4772.     
  4773.     ODULong            numValues;
  4774.     ODULong            j;
  4775.     ODValueType        valueName;
  4776.  
  4777.     fromSU->Focus(ev, (ODPropertyName) prop, kODPosUndefined, kODNULL, 0, kODPosAll);
  4778.  
  4779.     numValues = fromSU->CountValues(ev);    
  4780.     
  4781.     if ( numValues > 0)
  4782.         ODSUForceFocus(ev, toSU, prop, kODNULL);
  4783.     
  4784.     for (j = 0; j < numValues; j++)
  4785.     {
  4786.         fromSU->Focus(ev, (ODPropertyName) kODNULL, kODPosSame, kODNULL, 0, kODPosNextSib);
  4787.  
  4788.         valueName = fromSU->GetType(ev);
  4789.  
  4790.         ODSUForceFocus(ev, toSU, prop, valueName);
  4791.         ODULong toSize = toSU->GetSize(ev);
  4792.         toSU->DeleteValue(ev, toSize);
  4793.  
  4794.         ODDisposePtr(valueName);
  4795.         
  4796.         ODULong size = fromSU->GetSize(ev);
  4797.         ODPtr buffer = ODNewPtr(size);
  4798.         StorageUnitGetValue(fromSU, ev, size, (ODValue) buffer);
  4799.         StorageUnitSetValue(toSU, ev, size, (ODValue) buffer);
  4800.         ODDisposePtr(buffer);
  4801.     }
  4802. }
  4803.  
  4804. //------------------------------------------------------------------------------
  4805. // CopyDraftAnnotations
  4806. //------------------------------------------------------------------------------
  4807.  
  4808. static void CopyDraftAnnotations(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU)
  4809. {
  4810.     ODULong annotationPrefixLength = ODISOStrLength(kODPropPreAnnotation);
  4811.     ODULong metaDataPrefixLength = ODISOStrLength(kODPropPreODMetaData);
  4812.     
  4813.     fromSU->Focus(ev, (ODPropertyName) kODNULL, 
  4814.                             kODPosAll,
  4815.                             kODTypeAll,
  4816.                             0,
  4817.                             kODPosUndefined);
  4818.     ODULong numProperties = fromSU->CountProperties(ev);
  4819.     for (ODULong i = 1; i <= numProperties; i++) {
  4820.         fromSU->Focus(ev, (ODPropertyName) kODNULL,
  4821.                         kODPosNextSib,
  4822.                         kODTypeAll,
  4823.                         0,
  4824.                         kODPosUndefined);
  4825.         ODPropertyName propertyName = fromSU->GetProperty(ev);
  4826.         if (ODISOStrNCompare(propertyName, kODPropPreAnnotation, annotationPrefixLength) == 0)
  4827.             CopyProperty(ev, fromSU, toSU, propertyName);
  4828.         else if ((ODISOStrNCompare(propertyName, kODPropPreODMetaData, metaDataPrefixLength) == 0) &&
  4829.             (toSU->Exists(ev, propertyName, kODNULL, 0) == kODFalse)) {
  4830. #ifdef ODDebug_CloningAnnotations
  4831.             SetOutputMode(kWriteToFile);
  4832.             PRINT("metadata property %s does not exist in destination su.\n", propertyName);
  4833. #endif
  4834.             CopyProperty(ev, fromSU, toSU, propertyName);
  4835.         }
  4836.         ODDisposePtr(propertyName);
  4837.     }
  4838.  
  4839.     // Force copying of storage unit type property, which always exists so is
  4840.     // not copied in the iteration above.
  4841.     CopyProperty(ev, fromSU, toSU, kODPropStorageUnitType);
  4842. }
  4843.  
  4844. //------------------------------------------------------------------------------
  4845. // IsFrameObject
  4846. //------------------------------------------------------------------------------
  4847.  
  4848. static ODBoolean IsFrameObject(Environment* ev, ODDraft* draft, ODID objectID)
  4849. {
  4850.     ODBoolean isFrame = kODFalse;  ODVolatile(isFrame);
  4851.  
  4852.     TRY
  4853.     
  4854.         TempODISOStr suType = GetStorageUnitType(ev, draft, objectID);
  4855.     
  4856.         PRINT_CLONE("IsFrameObject: Type is %s\n", (ODISOStr) suType);
  4857.    
  4858.         isFrame = ODISOStrEqual(kODFrameObject, suType);
  4859.     
  4860.     CATCH_ALL
  4861.     ENDTRY
  4862.  
  4863.     return isFrame;
  4864. }
  4865.  
  4866. //------------------------------------------------------------------------------
  4867. // IsLinkObject
  4868. //------------------------------------------------------------------------------
  4869.  
  4870. static ODBoolean IsLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4871. {
  4872.     // Only link objects contain a kODPropLinkSource property
  4873.  
  4874.     TRY
  4875.  
  4876.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4877.     ODBoolean isLink = ((ODStorageUnit*) su != kODNULL) && (su->Exists(ev, kODPropLinkSource, kODNULL, 0));
  4878.  
  4879.     if ( isLink )
  4880.         PRINT_CLONE("Object ID %d is a link\n", objectID);
  4881.     
  4882.     return isLink;
  4883.  
  4884.     CATCH_ALL
  4885.     ENDTRY
  4886.     return kODFalse;
  4887. }
  4888.  
  4889. //------------------------------------------------------------------------------
  4890. // IsLinkSourceObject
  4891. //------------------------------------------------------------------------------
  4892.  
  4893. static ODBoolean IsLinkSourceObject(Environment* ev, ODDraft* draft, ODID objectID)
  4894. {
  4895.     // Only link source objects contain a kODPropLink property
  4896.  
  4897.     TRY
  4898.  
  4899.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4900.     ODBoolean isLinkSource = ((ODStorageUnit*) su != kODNULL) && (su->Exists(ev, kODPropLink, kODNULL, 0));
  4901.  
  4902.     if ( isLinkSource )
  4903.         PRINT_CLONE("Object ID %d is a link source\n", objectID);
  4904.     
  4905.     return isLinkSource;
  4906.  
  4907.     CATCH_ALL
  4908.     ENDTRY
  4909.     return kODFalse;
  4910. }
  4911.  
  4912. //------------------------------------------------------------------------------
  4913. // IsEitherLinkObject
  4914. //------------------------------------------------------------------------------
  4915.  
  4916. static ODBoolean IsEitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4917. {
  4918.     if ( IsLinkObject(ev, draft, objectID) )
  4919.         return kODTrue;
  4920.     else
  4921.         return IsLinkSourceObject(ev, draft, objectID);
  4922. }
  4923.  
  4924. //------------------------------------------------------------------------------
  4925. // IsNeitherLinkObject
  4926. //------------------------------------------------------------------------------
  4927.  
  4928. static ODBoolean IsNeitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4929. {
  4930.     if ( IsLinkObject(ev, draft, objectID) )
  4931.         return kODFalse;
  4932.     else
  4933.         return !IsLinkSourceObject(ev, draft, objectID);
  4934. }
  4935.  
  4936. //------------------------------------------------------------------------------
  4937. // SetStorageUnitType
  4938. //------------------------------------------------------------------------------
  4939.  
  4940. static void SetStorageUnitType(Environment* ev, ODDraftPermissions perms, ODStorageUnit* su, ODType suType)
  4941. {    
  4942.     if (perms == kODDPExclusiveWrite)
  4943.     {
  4944.         TempODType curType = ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL);
  4945.         if (!curType || !ODISOStrEqual(curType, suType))
  4946.             ODSetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, suType);
  4947.     }
  4948. }
  4949.  
  4950. //------------------------------------------------------------------------------
  4951. // GetStorageUnitType
  4952. //------------------------------------------------------------------------------
  4953.  
  4954. static ODISOStr GetStorageUnitType(Environment* ev, ODDraft* draft, ODID objectID)
  4955. {
  4956.     TRY
  4957.  
  4958.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4959.     if ( (ODStorageUnit*) su != kODNULL )
  4960.     {
  4961.         PreserveFocus fromFocus(ev, su);
  4962.  
  4963.         return ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL);
  4964.     }
  4965.  
  4966.     CATCH_ALL
  4967.     ENDTRY
  4968.     return kODNULL;
  4969. }
  4970.  
  4971. //------------------------------------------------------------------------------
  4972. // RootPartID
  4973. //------------------------------------------------------------------------------
  4974.  
  4975. static ODID RootPartID(Environment* ev, ODDraft* draft)
  4976. {
  4977.     TempODStorageUnit draftProperties = draft->AcquireDraftProperties(ev);
  4978.     return ODGetStrongSURefProp(ev, draftProperties, kODPropRootPartSU, kODStrongStorageUnitRef);
  4979. }
  4980.  
  4981. //------------------------------------------------------------------------------
  4982. // CheckClonedObject
  4983. //------------------------------------------------------------------------------
  4984.  
  4985. SOM_Scope void  SOMLINK CMDraftCheckClonedObject(CMDraft *somSelf, Environment *ev,
  4986.         ODID fromID,
  4987.         ODID toID,
  4988.         ODID originalID)
  4989. {
  4990.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4991.     CMDraftMethodDebug("CMDraft","CheckClonedObject");
  4992.     
  4993.     ODISOStr storageUnitType = kODNULL; ODVolatile(storageUnitType);
  4994.     
  4995.     SOM_TRY
  4996.     
  4997.     storageUnitType = GetStorageUnitType(ev, somSelf, fromID);
  4998.     
  4999.     PRINT_CLONE("CheckClonedObject: Type is %s\n", storageUnitType);
  5000.    
  5001.     if ( ODISOStrEqual(kODFrameObject, storageUnitType) )
  5002.     {
  5003.         _fAnyFrameCloned = kODTrue;
  5004.     }
  5005.     else if ( ODISOStrEqual(kODPartObject, storageUnitType) )
  5006.     {
  5007.         if ( (toID == originalID) && (RootPartID(ev, somSelf) == fromID) )
  5008.         {
  5009.             _fRootPartReused = kODTrue;
  5010.             PRINT_CLONE("CheckClonedObject: Root part reused\n");
  5011.         }
  5012.     }
  5013.  
  5014.     SOM_CATCH_ALL
  5015.     SOM_ENDTRY
  5016.  
  5017.     ODDisposePtr(storageUnitType);
  5018. }
  5019.  
  5020. //------------------------------------------------------------------------------
  5021. // SetOriginalDraft
  5022. //------------------------------------------------------------------------------
  5023.  
  5024. static void SetOriginalDraft(Environment* ev, ODDraft* targetDraft, ODDraft* originalDraft)
  5025. {
  5026.     TempODStorageUnit draftProperties = targetDraft->AcquireDraftProperties(ev);
  5027.     ODSetULongProp(ev, draftProperties, kODPropOriginalDraft, kODULong, (ODULong) originalDraft);
  5028. }
  5029.  
  5030. //------------------------------------------------------------------------------
  5031. // GetOriginalDraft
  5032. //------------------------------------------------------------------------------
  5033. // Returns kODNULL if the original draft is unknown.  This is the case when content
  5034. // was placed in the draft without cloning.
  5035.  
  5036. static ODDraft* GetOriginalDraft(Environment* ev, ODDraft* draft)
  5037. {
  5038.     TempODStorageUnit    draftProperties = draft->AcquireDraftProperties(ev);
  5039.     return (ODDraft*)ODGetULongProp(ev, draftProperties, kODPropOriginalDraft, kODULong);
  5040. }
  5041.  
  5042. //------------------------------------------------------------------------------
  5043. // OriginalCloneKindExists
  5044. //------------------------------------------------------------------------------
  5045.  
  5046. static ODBoolean OriginalCloneKindExists(Environment* ev, ODDraft* draft)
  5047. {
  5048.     TempODStorageUnit draftProperties = draft->AcquireDraftProperties(ev);
  5049.     return draftProperties->Exists(ev, kODPropOriginalCloneKind, kODULong, 0);
  5050. }
  5051.  
  5052. //------------------------------------------------------------------------------
  5053. // SetOriginalCloneKind
  5054. //------------------------------------------------------------------------------
  5055.  
  5056. static void SetOriginalCloneKind(Environment* ev, ODDraft* targetDraft, ODCloneKind cloneKind)
  5057. {
  5058.     TempODStorageUnit draftProperties = targetDraft->AcquireDraftProperties(ev);
  5059.     ODSetULongProp(ev, draftProperties, kODPropOriginalCloneKind, kODULong, (ODULong) cloneKind);
  5060. }
  5061.  
  5062. //------------------------------------------------------------------------------
  5063. // CMDraft: GetHeap
  5064. //------------------------------------------------------------------------------
  5065.  
  5066. SOM_Scope ODMemoryHeapID  SOMLINK CMDraftGetHeap(CMDraft *somSelf, Environment *ev)
  5067. {
  5068.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5069.     CMDraftMethodDebug("CMDraft","GetHeap");
  5070.  
  5071.     return _fHeap;
  5072. }
  5073.  
  5074. //------------------------------------------------------------------------------
  5075. // CMDraft: CreateLinkIterator
  5076. //------------------------------------------------------------------------------
  5077.  
  5078. SOM_Scope ODLinkIterator*  SOMLINK CMDraftCreateLinkIterator(CMDraft *somSelf, Environment *ev)
  5079. {
  5080.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5081.     CMDraftMethodDebug("CMDraft","CreateLinkIterator");
  5082.  
  5083.     CMLinkIterator* iter = kODNULL;
  5084.     ODVolatile(iter);
  5085.     SOM_TRY
  5086.     
  5087.         iter = new CMLinkIterator();
  5088.         THROW_IF_NULL(iter, kODErrOutOfMemory);
  5089.         iter->InitCMLinkIterator(ev, somSelf);
  5090.     
  5091.     SOM_CATCH_ALL
  5092.         
  5093.         ODDeleteObject(iter);
  5094.     
  5095.     SOM_ENDTRY
  5096.     
  5097.     return (ODLinkIterator*) iter;
  5098. }
  5099.  
  5100. //------------------------------------------------------------------------------
  5101. // CMDraft: CreateLinkSourceIterator
  5102. //------------------------------------------------------------------------------
  5103.  
  5104. SOM_Scope ODLinkSourceIterator*  SOMLINK CMDraftCreateLinkSourceIterator(CMDraft *somSelf, Environment *ev)
  5105. {
  5106.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5107.     CMDraftMethodDebug("CMDraft","CreateLinkSourceIterator");
  5108.  
  5109.     CMLinkSourceIterator* iter  = kODNULL;
  5110.     ODVolatile(iter);
  5111.     SOM_TRY
  5112.     
  5113.         iter = new CMLinkSourceIterator();
  5114.         THROW_IF_NULL(iter, kODErrOutOfMemory);
  5115.         iter->InitCMLinkSourceIterator(ev, somSelf);
  5116.         
  5117.     SOM_CATCH_ALL
  5118.         
  5119.         ODDeleteObject(iter);
  5120.     
  5121.     SOM_ENDTRY
  5122.     
  5123.     return (ODLinkSourceIterator*) iter;
  5124. }
  5125.  
  5126. //------------------------------------------------------------------------------
  5127. // itoa
  5128. //------------------------------------------------------------------------------
  5129. static void itoa(ODULong number, ODSByte* cstring)
  5130. {
  5131.     ODULong    i = 0;
  5132.     
  5133.     do {
  5134.         cstring[i++] = (ODSByte) (number % 10 + '0');
  5135.     } while ((number /= 10) > 0);
  5136.     cstring[i] = '\0';
  5137.  
  5138.     ODSByte    c;
  5139.     
  5140.     ODULong    j;
  5141.     
  5142.     for (i = 0, j = strlen(cstring)-1; i < j;i++, j--) {
  5143.         c = cstring[i];
  5144.         cstring[i] = cstring[j];
  5145.         cstring[j] = c;
  5146.     }
  5147. }
  5148.  
  5149. //------------------------------------------------------------------------------
  5150. // NewCMStorageUnit
  5151. //------------------------------------------------------------------------------
  5152.  
  5153. static CMStorageUnit* NewCMStorageUnit(ODMemoryHeapID heapID)
  5154. {
  5155.     SOMClass*    cmStorageUnitClass = somNewClassReference(CMStorageUnit);
  5156.     THROW_IF_NULL( cmStorageUnitClass );
  5157.     ODULong        size = cmStorageUnitClass->somGetInstanceSize();
  5158.     ODPtr        buffer = ODNewPtr(size, heapID);
  5159.     CMStorageUnit*    cmStorageUnit = (CMStorageUnit*) cmStorageUnitClass->somRenew(buffer);
  5160.     somReleaseClassReference ( cmStorageUnitClass );
  5161.     
  5162.     return cmStorageUnit;
  5163. }
  5164.  
  5165. //------------------------------------------------------------------------------
  5166. // PurgeAllStorageUnits
  5167. //------------------------------------------------------------------------------
  5168.  
  5169. static ODULong PurgeAllStorageUnits(Environment* ev, OpenHashTable* storageUnits, IDList* idList)
  5170. {
  5171.     ODID                    id;
  5172.     ODStorageUnit*            su;
  5173.     ODULong                    runningTotal = 0;
  5174.  
  5175. // idList is used to indicate whether we need to remove linkage between id and cmObject
  5176.  
  5177.     OpenHashTableIterator    suIter(storageUnits);
  5178.     for (suIter.First(&id, &su); suIter.IsNotComplete(); suIter.Next(&id, &su)) {
  5179.         if (su->GetRefCount(ev) != 0) {
  5180.             if (idList) // purge should release CMObject, signal that by removing from idList
  5181.                 idList->Remove(id); 
  5182.             runningTotal += su->Purge(ev, 0);
  5183.         }
  5184.     }
  5185. /*
  5186.     for (suIter.First(&id, &su); suIter.IsNotComplete(); suIter.Next(&id, &su)) {
  5187.         if (su->GetRefCount(ev) == 0) {
  5188.             suIter.RemoveCurrent();
  5189.             delete su;
  5190.         }
  5191.     }
  5192. */
  5193.     // ShrinkToFit() allocates new tables first, and this aggravates
  5194.     // low memory conditions during Purge().
  5195.     // storageUnits->ShrinkToFit(/*extraSlots*/ 0);
  5196.         
  5197.     return runningTotal;
  5198. }
  5199.  
  5200. //------------------------------------------------------------------------------
  5201. // CMDraft: PartInstantiated
  5202. //------------------------------------------------------------------------------
  5203.  
  5204. SOM_Scope void  SOMLINK CMDraftPartInstantiated(CMDraft *somSelf, Environment *ev,
  5205.         ODPart* realPart)
  5206. {
  5207.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5208.     CMDraftMethodDebug("CMDraft","PartInstantiated");
  5209. }
  5210.  
  5211. //------------------------------------------------------------------------------
  5212. // CMDraft: PartDeleted
  5213. //------------------------------------------------------------------------------
  5214.  
  5215. SOM_Scope void  SOMLINK CMDraftPartDeleted(CMDraft *somSelf, Environment *ev,
  5216.         ODPart* realPart)
  5217. {
  5218.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5219.     CMDraftMethodDebug("CMDraft","PartDeleted");
  5220. }
  5221.  
  5222. //------------------------------------------------------------------------------
  5223. // CMDraft: SwapPart
  5224. //------------------------------------------------------------------------------
  5225.  
  5226. SOM_Scope void  SOMLINK CMDraftSwapPart(CMDraft *somSelf, Environment *ev,
  5227.         ODPart* part)
  5228. {
  5229.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5230.     CMDraftMethodDebug("CMDraft","SwapPart");
  5231.  
  5232.     SOM_TRY
  5233.         OpenHashTableIterator     i(_fPersistentObjects);
  5234.         ODStorageUnitID            id;
  5235.         ODPersistentObject*        object;
  5236.         ODFrame*                frame;
  5237.  
  5238.         somSelf->Externalize(ev);
  5239.         
  5240.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  5241.             if ( strcmp(object->somGetClassName(), kFrameClassName)==0 ) {
  5242.                 frame = (ODFrame*)object;
  5243.                 if ( frame->IsSubframe(ev) == kODFalse )
  5244.                     frame->PrepareToSwap(ev, part);
  5245.             }
  5246.         }
  5247.     SOM_CATCH_ALL
  5248.     SOM_ENDTRY
  5249. }
  5250.  
  5251. //------------------------------------------------------------------------------
  5252. // CMDraft: InitScriptingIDManager
  5253. //------------------------------------------------------------------------------
  5254. //
  5255. // This method should be called to create and initialize the Scripting ID Manager
  5256. // just prior to calling a Scripting ID Manager method.  Many drafts, such as
  5257. // data interchange drafts and non-top document drafts, will never use the
  5258. // Scripting ID Manager, so its wastefull to create one for every draft.
  5259.  
  5260. SOM_Scope void  SOMLINK CMDraftInitScriptingIDManager(CMDraft *somSelf, Environment *ev)
  5261. {
  5262.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5263.     CMDraftMethodDebug("CMDraft","InitScriptingIDManager");
  5264.  
  5265.      if ( _fScriptingIDMgr == kODNULL )
  5266.      {
  5267.         SOM_TRY
  5268.             _fScriptingIDMgr = new(_fHeap) ScriptingIDManager; // "new" THROWS for non-SOM objects
  5269.             _fScriptingIDMgr->InitScriptingIDManager(ev, _fHeap, somSelf);
  5270.         SOM_CATCH_ALL
  5271.             if ( _fScriptingIDMgr != kODNULL )
  5272.             {
  5273.                 delete _fScriptingIDMgr;
  5274.                 _fScriptingIDMgr = kODNULL;
  5275.             }
  5276.         SOM_ENDTRY
  5277.     }
  5278. }
  5279.  
  5280. //------------------------------------------------------------------------------
  5281. // CMDraft: DropPersistentObjectID
  5282. //------------------------------------------------------------------------------
  5283.  
  5284. SOM_Scope void  SOMLINK CMDraftDropPersistentObjectID(CMDraft *somSelf, Environment *ev,
  5285.         ODPersistentObject* object)
  5286. {
  5287.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5288.     CMDraftMethodDebug("CMDraft","DropPersistentObjectID");
  5289.  
  5290.     SOM_TRY
  5291.  
  5292.     if ( _fPermissions == kODDPExclusiveWrite )
  5293.     {
  5294.         CMStorageUnit* cmsu = (CMStorageUnit*) object->GetStorageUnit(ev);
  5295.         
  5296.         if ( cmsu != kODNULL )
  5297.         {
  5298.             somSelf->InitScriptingIDManager(ev);
  5299.             _fScriptingIDMgr->DropScriptingID(ev, cmsu->GetObjectID(ev));
  5300.         }
  5301.     }
  5302.  
  5303.     SOM_CATCH_ALL_ENDTRY
  5304. }
  5305.  
  5306.